Final Wiring ############ .. include:: /header.inc .. vim:filetype=rst spell: With the final design laid out in some detail, with all the needed components identified, and the wires we need to set up itemized, all that remains is to wire up this diagram, then place on top of everything a control unit that can direct the action. We have seen enough code and examples to do that job To help in visualizing how we will interconnect all the parts we have constructed, here is a diagram showing how pointers are being used to hook up our circuit. .. image:: /latex/tikz/sim.png :align: center :width: 600 In this diagram, we see two generic parts, each with a set of input pins and output pins. All parts provide a single ``tick`` method, which we now set up with a single integer parameter that will be set by our control unit. Each part is connected to a wire. The attachments are through a pin. Each part has a C++ ``vector`` of pointers to pins, so we dynamically allocate pins as needed, and store the address of each pin in the appropriate vector. In the diagram, these pointers are simply numbered. The pins maintain four pieces of information: * ``n`` - a string naming the pin * ``p`` - a pointer to the part thta owns the pin * ``w`` - a pointer to the attached wire * ``v`` - the current value of the signal on that pin We obviously have a bunch of pointers in this design, but this scheme makes building our machine easy. Just watch! The Simulator System ===================== And, just for reference, here is the simulator system, as designed up to this point. It still needs work, but this is enough ot start working through the instruction set to make sure the machine is complete (it is not!) .. image:: /latex/tikz/avrsim.png :align: center Testing things ============== Throughout this course, we have emphasized testing the parts you need to build to set up this simulator. Here is a conceptual diagrm of the test setup we want to build. In hardware design, you hook up a part to a "test fixture" then fire it up and make sure it works. The fixture is designed so you can attach the inputs, and generate signals to be sent to the unit, then you record the outputs and decide if the part is working correctly. .. image:: /latex/tikz/fixture.png :align: center :width: 400 Stage Design ************ Earlier, we describes each stage as a big component, with a bunch of parts and wires inside. Each stage "super-component" can have its own control unit that directs the actions needed for just that stage. As you may have noticed, execute and store may need some actions to happen back in the decode stage. The control unit can handle that, with a little thought. It still seems a good idea to build our final design as a set of super-components with inputs and outputs defined. I added dashed lines at the points in our design where the stage boundaries logically should be placed. One way to actually design this system is to simply place pins at those spots where wires cross the boundaries, and let those pins be shared by both stages. This would avoid adding more wires to the design. Our big master simulation loop them would only need to call "tick" on each super-component, and the data items would be recorder on the pins. There is no wire leaving that pin. So, when we run "tick" on the following stage, reading the pin would let that next stage see the new data value. Visually, we simple glue one unit up to another unit with no wire in between. It should work! Control Logic ************* We have talked about the control unit, and shown example code that we can use to make things happen. Logically, the control unit sits above this design, with the ability to trigger action in any component or wire when needed. The decode unit will let the control unit know which instruction we are processing, and the control unit will consult some kind of data store telling it exactly how to sequence parts or wires to make that instruction happen. MicroCode ========= Many processors work this way. There is a table with bits for each component in the system. .. note:: Wires are not really controlled. When signals change on an input to a wire, the signals immediately travel to the attached output points with no control needed. We could model this behavior by calling the ``tock`` method on any attached output wire whenever we change the output value on the driving pin. The "microcode" table is often hard coded into the chip. There might be a bit for every controllable gadget in the machine. There will be one potentially large list of bits for each step in moving data through the machine for each instruction. It can take a different number of steps to complete processing of every instruction, so this table can be a bit complicated to build. One solution to this design issue is to create a vector of micro-instructions for every assembly language instruction we need to process. That vector will hold a list of parts needing to be triggered in the correct order to sequence that machine. This vector will be used by the control unit to decide which parts to activate by calling the ``tick`` method. Since control nits provide additional signals to configure devices like multiplexors, it makes sense to change our implementation of the ```tick`` method, and provide a simple parameter that can be used for this purpose. A simple 8-bit data item will do for our machine. .. code-block:: c++ void tick(uint8_t ctrl); We will modify the ``tick`` methods when needed to use this new signal properly. The Wiring Job ************** Actually wiring the machine is just a chunk of boring code connecting wires to components using methods we have already set in place. This step can be automated, and "Hardware Description Languages" essentially do exactly that. For our purposes, there is a simple way to do the tedious wiring. Net Lists ========= Describing a circuit for some electronic gadget is often done by creating a "net list". This is a simple text file containing a list of parts, and definitions of the wire connections needed between those parts. In our case, we have names for all the parts (classes) we have assembled, and we have names for each pin we attach to that component. Our "net list" can be pretty simple to write, and simple to implement. Let's give it a try. Here is a "net list" file we can use: .. literalinclude:: wiring/avrsim.net :linenos: :caption: avrsim.net All the pieces of this file are separated by spaces, making reading it using C++ easier. .. literalinclude:: wiring/sim_builder.cpp :linenos: :caption: /lib/sim_builder.cpp .. note:: This is hardly the best example of a parser for this application, but it works for well-formed data files. If we had more time, I would show you real parsing code here. To build the machine from this snippet of code, we use a ``vector`` to hold all of our parts, and another vector to hold all of our wires. Each part and wire needs to be created dynamically, unless we want to just build an array of those objects big enough for our simulator. (We do know how many of each we need - now!) Tick Tock ********* After we assemble the machine, our only remaining task is to figure out the control mechanism. Since we will have a list (vector) of parts and wires, and each of those provides a method to activate that gadget, running our machine is as simple as this: .. code-block:: c++ for(int p = 0; p < num_parts; p++) if (???) parts[p].tick(); for (int w=0; w<-num_wires;w++) if (???) wires[w].tock(); Seems simple enough. Except for filling in those "???" logical expressions. Cleared for Take Off ******************** OK, so I am a pilot. The most fun moment in flying is when you are sitting there in an airplane with everything you need ready, and you are ready to take off. In our case, you have all the parts we need, and a diagram showing how to connect all those parts with some wires, and a plan for controlling everything. Let's see if we can make this beast run!