Step 7: Inverters

Read time: 11 minutes (2859 words)

Our first real part is the Inverter. Formally, this device is a hardware implementation of George Boole’s “not” operation. This device has a single input pin, and a single output pin. All it does inside is read the input signal, flip it (complement) and write that new signal back out on the output pin. How hard can this be to implement? For our first real device, the input will be a single bit (a zero or a one). The output will also be a single bit. Formally, we could handle more bits, and compliment each bit individually, producing an output result. We will do that later. For now, we will stick with this single bit version.

C++ Inheritance

To implement this device we need to set up a class that “inherits” everything we defined in the generic component class. Essentially, this new class will have all the capabilities of the component class plus new features we add in in this derived (child) class.

Inheritance is a complex topic in C++, but in our case all we really need to do is provide a new constructor that sets up our new part, and a new version of the tick routine that does the real work we need. We will set up the required input and output pins in the constructor for this class, so objects we create later will be ready to run!

Inverter Class Specification

Here is our new part header file:

include/Inverter.h
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// Copyright 2018 Roie R. Black
#pragma once
#include <string>
#include "Component.h"

class Inverter : public Component {
 public:
    // constructors
    explicit Inverter(std::string n);

    // mutators
    void tick(void);
};

The “inheritance” we are doing here can be seen on line 5. The normal class declaration line has new stuff after the class name. We place a colon, an access specifier (public in this case), then the name of the class we are extending. Of course, we need to include the header file for that generic class so this name will be recognized by the compiler.

Essentially, that first line in the constructor will pass on the Inverter name to the constructor from the Component class, where that name will be registered. Inheritance lets you add new attributes or methods, or override methods in the base class with new methods in the derived class. We cannot delete things from the base class.

Testing the Inverter

Testing the inverter simply involves checking that it does the work needed when that tick routine is called. All we need to do is set the input pin to some value (remember that this is a single bit input, so the only legal values are zero and one). Then we call the tick routine and make sure the output changes to the opposite of the set value.

Here is the code:

tests/test_inverter.cpp
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Copyright 2018 Roie R. Black
#include <catch.hpp>
#include "Inverter.h"

TEST_CASE("test inverter constructor", "parts") {
    std::string NAME = "CPUtest";
    Inverter inv(NAME);
    REQUIRE(inv.get_name() == NAME);
}

TEST_CASE( "test_inverter operation", "parts" ) {
    std::string name = "INV";
    Inverter inv(name);
    Pin * inpin = inv.get_in_pin("IN");
    Pin * outpin = inv.get_out_pin("OUT");
    inpin->set_val(1);
    inv.tick();
    REQUIRE( outpin->get_val() == 0 );
    inpin->set_val(0);
    inv.tick();
    REQUIRE( outpin->get_val() == 1 );
}

Inverter Implementation

I suspect you can figure out the implementation code for this device. Since the hard work has already been taken care of in the generic Component class, all we need here is a new constructor that sets up the required pins, and the new tick method:

lib/Inverter.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
// Copyright 2018 Roie R. Black
#include "Inverter.h"
#include <iostream>
#include <string>

// constructor
Inverter::Inverter(std::string n):Component(n) {
    this->add_in_pin("IN");
    this->add_out_pin("OUT");
}

// TICK: perform component processing
void Inverter::tick(void) {
    Pin *inpin = this->get_in_pin("IN");
    Pin *outpin = this->get_out_pin("OUT");
    uint16_t ival, oval;

    if (inpin) {
        ival = inpin->get_val();
        oval = ival == 0 ? 1 : 0;
    }
    if (outpin) {
        outpin->set_val(oval);
    } 
}

Note

Look closely at that single line that “flips” the input bit. This is called a “C++ Conditional Expression”. Basically is has this form:

expr1 ? expr2 : expr3;

the statement returns the result of evaluating expr2 if evaluating
expr1 results in ``true``, otherwise it returns the result on
evaluating expr3. It is just a shortened up if-then-else piece of code.

Running the tests now shows that we have a real, admittedly simple, digital part to play with. Let’s set up a simple circuit and see if we can make something work!