# Modeling Wires¶

Read time: 33 minutes (8354 words)

Note

Beginning with this lecture, we will start Lab4. Remember to tag your commits as indicated.

So far, we have been moving data the traditional way, by letting the objects be manipulated directly by some controlling code. We need to stop doing that and add the wires between our components. The next few steps make that transition.

## Step05: Introducing Wires¶

We have a significant mental switch to make here. So far, the terms read and write have been viewed from the perspective of controlling code making things happen. As we said earlier, that has to change. From this point on, those verbs (actions) will be viewed as happening inside of a component. When the component writes, data is leaving the component. When the component reads, data that has arrived at that component from the outside world is read, pulled into the inside of the component where it will be processed to produce new outputs.

In both cases, a new wire gadget will be involved.

Wires will be simple objects that we “attach” to other components in our system. We will use pointers to connect components to wires. As a start, we will store the address of the “attached” component in the wire object. We need a way to get the addresses of our two components, and attach the wire to both of them.

Here is what out new main function will look like:

src/main.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 #include #include "Component.h" // create parts Component c1("X",5), c2("Y",0); Wire c1_c2; void build_circuit( void ) { c1_c2.attach_in(&c1); c1_c2.attach_out(&c2); } int main( int argc, char *argv[] ) { std::cout << "attinysim v(0.5.0)" << std::endl; std::cout << "running ..." << std::endl; // build the circuit build_circuit(); // make the data move c1_c2.tick(); std::cout << "done!" << std::endl; } 

Notice that we still build two component objects, but we also build a new wire, with a name to remind us which components we are attaching to the two ends. In this case, c1 will be writing to the wire, and c2 will be reading from the wire. Notice, also, that we hook everything together in the build_circuit function, using methods in the Wire class. This function connects the two ends of the wire to the correct components, using their addresses.

### Component Modifications¶

Here is the new Component definition:

include/Component.h
  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #pragma once #include #include "Wire.h" class Component { public: Component(std::string n, int val); friend class Wire; private: std::string name; int data; std::string get_name(); int read(int val); int write( void ); }; 

The friend specification in this file may be new to you. Basically, a friend class is allowed to access attributes and methods in another class that are marked as private. This is yet another neat way to restrict access to only that part of the application code that really needs that access. In our machine we are making as much of the Component class as we can private. But, we will allow the Wire class to reach in and work with things inside that protective wrapper.

Here is the component implementation:

lib/Component.cpp
  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include #include "Component.h" Component::Component( std::string n, int val ) { data = val; name = n; } int Component::write( void ) { return data; } int Component::read( int val ) { return data = val; } std::string Component::get_name( void ) { return name; } 

### Wire Implementation¶

And, finally, here is the Wire class definition:

include/Wire.h
  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #pragma once #include class Component; class Wire { public: Wire(); void attach_in(Component *c_in); void attach_out(Component *c_out); void tick( void ); private: int data; Component *in; Component *out; std::string source, dest; void read(void); void write( void ); }; 

There is definitely something new here. This wire object supports a new method called tick. We have been describing the controller as a component that sends signals to other components in the form of a tick method. Here, we are asking the wire component to respond to a tick call and do something.

Does that make any sense.

Recall what we are modeling here. It is the simple transfer of data from one place to another. The components have no real work to do yet. But the wire definitely has work to do. It must transfer the data between the components.

What we are doing here is giving the wire the responsibility for reading and writing data from the individual components. Real wires have no “intelligence”, so it really is not a wise design decision to make them do anything. It would definitely be better to move those actions into the component. However, there is something interesting that will happen if we leave this design as is, at least for now. We may revisit that decision later.

Here is the wire implementation:

lib/Wire.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 45 #include #include #include "Wire.h" #include "Component.h" // constructor Wire::Wire() { data = -1; //attachments in = NULL; out = NULL; } // Accessors do not modify object state void Wire::write( void ) { // send wire data to output dest = out->get_name(); out->read(data); std::cout << source << "-(" << data << ")->" << dest << std::endl; } // mutators modify object state void Wire::read(void) { // load wire data from input data = in->write(); source = in->get_name(); } void Wire::attach_in(Component *c_in) { // connect component to inut side in = c_in; } void Wire::attach_out(Component *c_out) { // connect component to output side out = c_out; } void Wire::tick( void ) { // on demand get new data and deliver it read(); write(); } 

Does it still work? Let’s see:

$make run ./cosc2325 attinysim v(0.5.0) running ... X-(5)->Y done!  It looks like we are still running fine. This time with a completely new way to accomplish our data transfer. ### Reviewing Step05¶ We are definitely making progress. The transfer of data is now happening by a simple, direct, movement of that data over a simulated “wire”. We have instrumented our code so we can observe that transfer to make sure things are happening in a logical order. Our machine is still pretty primitive, but it is headed in the right direction! The wire is definitely in control of the action in this version. Wires are not in control of anything in a real system. They are just conducting pathways over which electrons flow from place to place. They are hugely important, but they have no intelligence. So, we really should get rid of that part of our design and transfer the intelligence into the components, where that makes more sense. However, we will be able to watch things work in a very simple way using this design, so I am leaving that code as is. In our next few steps, we will start making the machine “run” and set up a simulated oscilloscope so we can visually watch things go! This should be fun! Note Commit this version. Tag it as v0.5.0 ## Step06: Control Logic¶ Now that we have a class that will model connections between our components, we need to look at how we are building the simulator. ### Reviewing the Simulation¶ Our Wire class has no real purpose other than to facilitate the movement of data from register to register in our simulator. At this point, we are using the term “register” to mean a component that can hold a piece of information internally. The “register” does not perform any work on that data (yet), it simply hangs on to it. Wires, in general, can have only one input source at a time. They may be read by many components. In real circuits, there is a limit on the number of components you can attach to a wire, but we will ignore that limitation. For now, we will focus on a single input and a single output for the wire objects. We will let the wire objects respond to the clock ticks as well, which is not something normally done in simulators. My idea here is that we will treat our clock as a two stage device, sending “tick” signals to all system components, then sending “tock” signals to all wires to have them move data between components. In a real circuit, the wire just sits there, transferring signals over their length to any attached components, so this model seems reasonable, I am setting things up this way so we can watch our data moving over the wires from place to place. We will eventually build two kinds of output displays: a simple console log of the actions taken, and a graphical system we can use to visualize what is going on, using a display similar to those found on oscilloscopes. ### Adding a Machine Class¶ We need to pull building the machine out of our main function, and set up the control logic for the simulator. We will not call this component the controller, since it is going to be responsible for the construction and operation of the entire machine. We will simply call it the Machine! Here is the new Machine class definition: include/Machine.h   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #pragma once #include "Component.h" #include "Wire.h" class Machine { public: Machine( void ); void build( void ); void run( void ); friend class wire; private: // parts needed Component *c1; Component *c2; Wire *c1_c2; };  There is something new in here. Instead of creating our component and wire objects statically, by simply declaring them in the code, I am building everything dynamically, at run time. We store the address of these new objects in a pointer variable. That change means I no longer can call methods using a simple dot notation. Instead, we need to use the -> notation, which simply means “follow this pointer to an object, and call a method you find there”. Here is the implementation of the Machine class: lib/Machine.cpp   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include "Machine.h" #include "Component.h" #include "Wire.h" Machine::Machine( void ) { } void Machine::build( void ) { c1 = new Component("C1",5); c2 = new Component("C2", 0); c1_c2 = new Wire(); c1_c2->attach_in(c1); c1_c2->attach_out(c2); } void Machine::run( void ) { c1_c2->tick(); }  Make sure you understand this new notation! ### Component Class Modifications¶ The new way of creating our components and wires means we need to alter the component files slightly: include/Component.h   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #pragma once #include #include "Wire.h" class Component { public: Component(std::string n, int val); friend class Wire; private: std::string name; int data; std::string get_name(); int read(int val); int write( void ); };  lib/Component.cpp   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include #include "Component.h" Component::Component( std::string n, int val ) { data = val; name = n; } int Component::write( void ) { return data; } int Component::read( int val ) { return data = val; } std::string Component::get_name( void ) { return name; }  ### Modifications to main¶ With our new Machine class in place, here is the modified main.cpp file src/main.cpp   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include #include "Machine.h" Machine m; int main( int argc, char *argv[] ) { std::cout << "attiny85sim v(0.6.0)" << std::endl; std::cout << "running ..." << std::endl; // construct the machine m.build(); // make data move m.run(); std::cout << "done!" << std::endl; }  This is much cleaner. All of the setup logic is now gone from main. All main needs to do is create a Machine object, initialize that object (by building the system), and then direct that object to run! Obviously, we need to test this version: $ make clean
rm -f cosc2325 src/main.o lib/Component.o lib/Machine.o lib/Wire.o

$make g++ -c -Iinclude -o src/main.o src/main.cpp g++ -c -Iinclude -o lib/Component.o lib/Component.cpp g++ -c -Iinclude -o lib/Machine.o lib/Machine.cpp g++ -c -Iinclude -o lib/Wire.o lib/Wire.cpp g++ -o cosc2325 src/main.o lib/Component.o lib/Machine.o lib/Wire.o  And run it: $ make run
./cosc2325
attiny85sim v(0.6.0)
running ...
C1-(5)->C2
done!


Note

You should commit this version of the code now. Tag it as version v.0.6.0

## Step07: Modeling Time¶

Our simulation is making progress, but it is only a one-shot “tick” system. We need a way to make this machine run for some period of time. The change to do that just needs to add a simple loop in the run method in our Machine class:

### Machine Class¶

The machine class has one new function in addition to the clock loop. It will start the log output. At this point, we only display console messages. The run method has the needed code.

The class specification file is unchanged

The implementation adds output in the run method. This code starts a line of output by displaying a clock “tick” number. The run method is now set up to run for several cycles. Since our simulator is not doing any real work for now, the output will be a set of repeated lines.

lib/Machine.cpp
  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include #include "Machine.h" #include "Component.h" #include "Wire.h" Machine::Machine( void ) { } void Machine::build( void ) { c1 = new Component("C1",5); c2 = new Component("C2", 0); c1_c2 = new Wire(); c1_c2->attach_in(c1); c1_c2->attach_out(c2); } void Machine::run( void ) { int max_ticks = 10; for( int time = 0; time < max_ticks; time++ ) { std::cout << "t" << time << ": "; c1_c2->tick(); } } 

### Main Function¶

The main function remains unchanged, except for the version number:

src/main.cpp
  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include #include "Machine.h" Machine m; int main( int argc, char *argv[] ) { std::cout << "attiny85simc v(0.7.0)" << std::endl; std::cout << "running ..." << std::endl; // build the machine m.build(); // make the data move m.run(); std::cout << "done!" << std::endl; } 

Let’s check out this version:

$make clean rm -f cosc2325 src/main.o lib/Component.o lib/Machine.o lib/Wire.o  $ make
g++ -c -Iinclude -o src/main.o src/main.cpp
g++ -c -Iinclude -o lib/Component.o lib/Component.cpp
g++ -c -Iinclude -o lib/Machine.o lib/Machine.cpp
g++ -c -Iinclude -o lib/Wire.o lib/Wire.cpp
g++ -o cosc2325 src/main.o lib/Component.o lib/Machine.o lib/Wire.o


And run it:

\$ make run
./cosc2325
attiny85simc v(0.7.0)
running ...
t0: C1-(5)->C2
t1: C1-(5)->C2
t2: C1-(5)->C2
t3: C1-(5)->C2
t4: C1-(5)->C2
t5: C1-(5)->C2
t6: C1-(5)->C2
t7: C1-(5)->C2
t8: C1-(5)->C2
t9: C1-(5)->C2
done!


Note

You should commit this version of the code now. Tag it as version v.0.7.0