Step 5: Adding the Wire Class ############################# .. include:: /header.inc .. vim:filetype=rst spell: This class is going to be a bit harder to set up than the Pin class. We need help from part of the C++ Standard Template Library to set up a wire. As we discussed earlier, a wire can be driven by only one signal source, but it can deliver that signal to any number of other parts. The input to a wire is an output signal from some part. The signal will be sitting on an output pin attached to that part. The signal travels over the wire, then reaches another part where it will connect to an input pin on some other part. In real digital hardware, one wire can usually drive no more than about 10 other parts. This is called the ``fan-out`` limit and it is the result of needing enough power in the signal to adequately trigger a bunch of inputs on other parts. We will not worry about that here, but in real hardware, you need to pay attention to that limit. We will set up wires so they "point" to a pin. The attachment will be a pointer to a pin. We need one pointer to a Pin object on one side of the wire. This one pin will "drive" the wire. That one is simple to set up. We just add an attribute that is a pointer to a pin. On the other end of the wire we need a way to attach a bunch of pins. A simple array of pin pointers will not do, because we do not know how many attachments we might need. What we need is an array that can grow at run-time. C++ provides exactly that kind of data structure in the C++ STL Vector class. Internally, a vector is something like a linked list of objects, except that this list is accessed more like an array. A vector is a ``template`` class, something you may not have used before. Basically a template is like a normal class, but there is a data type parameter that you specify when you create objects using the class. C++ Vectors *********** Objects of the vector class can be accessed using simple array notation, and we can ask how many items are currently in the "array". The new feature is the ability to add items to the array at runtime. The method we use for this is named ``push_back``. Here is some example code that demonstrates how we will use the vector class to create out output attachment points. .. code-block:: c++ #include #include "Pin.h" Pin * driven; std::vector drives; Pin pin1("P1"); Pin pin2("P2"); Pin pin3("P3"); driven = &pin1; drives.push_back(&pin2); drives.push_back(&pin3); The key piece of code here is that data type definition inside of the angle brackets above. Those create a specific vector class that will be an array of pointers to pins. .. note:: This is just an example, the actual code will be shown later. Here, we are recording the address of a pin object in the ``drives`` object, and adding the addresses of the needed pins in the ``drives`` vector object. The Wire Specification ********************** Here is the specification of our Wire class: .. literalinclude:: code/cpu-factory5/include/Wire.h :linenos: :caption: include/Wire.h It is not common to name wires in digital circuits, you tend to focus on the names of the pins used to hook things up. I am adding a name for later use. Again, it gives us a simple test of a constructor. Notice that we provide the ``tock`` method we will use to move data along the wire. There are also methods we can use to manufacture a specific wire, adding the attachments on both ends as needed. Finally, there are methods to retrieve the names of the pins we end up attaching to a wire. This will be used in checking that our machines work properly later when we start building real circuits using this code. Testing the Wire **************** With the header defined, we can write some simple tests. We already have a basic constructor, but we need to test the value on the wire. This logic is identical to what we set up for testing the pin class. The new methods will take some setup to exercise. Here is the code I came up with: .. literalinclude:: code/cpu-factory5/tests/test_wire.cpp :linenos: :caption: tests/test_wire.cpp .. note:: This test code is certainly not complete. I should add checks that verify that when we attach a wire to pin objects, e can retrieve the names of the attached pins. Adding such tests enhances the "coverate" of our tests. We will add a tool to check your test coverage later. Wire Class Implementation ************************* With the test in place, it is time to add the Wire class implementation code. This looks worse than it is. All we need to remember is how a wire works in our system. We have provided a ``tock`` method that will make the wire perform its work. When that method is called, the wire will read the current signal on the ``driven`` pin, and copy that value onto each of the ``drives`` pins. It is pretty simply, but you need to remember that each attachment is a pointer to a pin somewhere, and we need pointer notation to access the pin methods. Here is the code we need to implement this class: .. literalinclude:: code/cpu-factory5/lib/Wire.cpp :linenos: :caption: lib/Wire.cpp Run your tests now, and make sure your wire works as expected! We have two of the three basic classes we need to start our simulation work. The next class on our list is the generic ``Component`` class. We will not be creating objects using this class in our simulator. Instead, we will inherit from this class and create the real components we need.