Simulator Basics

Read time: 42 minutes (10623 words)

Scene: Nick’ basement.

Alan: Hey Nick, let’s build a computer

Ada: Does that mean we are going to Fry’s?

Alan: No, I have this cool FPGA at home. We will build one using that!

Ada: That chip must be expensive!

Nick: I think you can find them for around 50 bucks. Sounds cool!

One of the major course objectives is for you to build a simple simulator for a real computer. While I would love to build a real computer in this class, using one of those FPGA boards, that would be asking a bit much. Instead, we are going to build as much of a simple simulator as we can.

No, we will not simulate anything as complex as a Pentium. We can, however, write a simple simulation program, using C++ tools, that mimics what a real machine does. And, mimics it so well we can actually run some code on it!

Hey, this is the kind of programming I really like, it is fun! Maybe not as cool as blowing up space aliens, but cool enough! You will learn a few new and useful programming tricks in this simulation as well!

Here is one of my FPGA boards:

../_images/basys-fpga.png

Building a Computer

What we need to do is find a way to write a program where we can assemble a bunch of fairly simple simulated components and interconnect those components with something that simulates wires.

A real computer is constructed in exactly this way. Each component part just sits there, with no idea that it is part of a computer. There will be a set of wires attached to each component allowing signals to travel from component to component.

Hey, we can do that in code! Simulation does not sound too hard!

Components

We will view each component as a simple “Black Box”. That means that what happens inside is hidden. We can envision a box inside of which some kind of magic happens. We do not know, and really do not care how it does its magic. We provide a set of pathways we can use to deliver input signals to this component. We will also provide another set of output pathways that can carry output signals away from the component. We can use those output signals however we wish. That component does not know, and does not care, where the input signals came from, nor does it care where its output signals go. It just sits there waiting for signals it can process.

By the way, the transformation work takes some amount of time to complete. In our last lecture, we decided to deal with time by waking up a specific moments and checking our system to see what state it is in.

Since we are not allowed to look inside of the components, I guess that leaves us with only wires to examine. That is exactly how I learned how all this computer stuff works. I built a real computer out of a few fairly simple parts, connected them together with wires, and hooked up test equipment to see what ws happening on those wires!

This is a shot of a “wire-wrapped” board, sort of like the mess I was building back when home computers were very new:

../_images/wire-wrap.png

Today, building test circuits is much simpler. As we shall see, much of the design work is done in software!

If this was a course in electronics, we might actually build our own computer. That is not as far-fetched as you might think.

Modeling the Internal Work

Each component reacts to incoming signals in some way. More than likely, it generates a set of output signals using just those input signals, which leave the component and head off to some other component in the system.

C++ was designed to help us model real things from our human world. We call those things objects. Here we will call them components. We will simulate each basic part we need for our computer using a single C++ class. The C++ class allows us to describe the component, then manufacture a bunch of those components (objects) on demand, as we need them.

By now, you know how to set up a C++ class. You also know how to build one or more objects using that class. We will assembly our simulated computer using a set of class definitions, and build as many components as we need.

Simple, huh?

Well, there is one small wrinkle. These component objects will not be calling other component objects to get things done. That simply is not how a real computer works.

How Components Work

As we indicated earlier, each component in real computer just sits there watching its input signals. As they change, it reacts to them, and generates some new set of output signals. The internal work needed to create that output signal set takes some time to complete.

All of these signals travel from place to place over wires. The output signal from one component becomes the input signal for some other component.

What we have to do is control all of this action, and make the system of components do our bidding. Basically, we need to teach this collection of parts to do the “dance”!

We just need to figure out how to make a simulated signal trigger action in a simulated component. Then we have to teach our components how to do a few simple transformations on those input signals to produce the resulting output signals we want.

Add all of this up, and we hope to get a computer!

Note

There are many ways to build a simulation. I am going to show you a way that behaves as much like a real computer as I can come up with. It is not too hard to understand, but you will be using a scary (for beginners) C++ construct called a pointer

Scene: Coffee shop

Alan: Hey Nick, what is the difference between a variable and an address?

Nick: A variable is a container with a name. The compiler converts the name into the address of the first memory slot it will assign to the that container. The variable’s value will be stored at that address. The variable is the container holding a value, the address is just where that container lives in memory.

Alan: Correct, but way too technical. Ada! Your turn!

Ada: “Nick” is the name of a weird “variable”. Nick lives at some address. An address is a house number. If Nick is late to our meeting, I use his address to find Nick’s house, bang on the door, and, when the door opens, drag his carcass to our meeting!

Alan: I like that one! However, does that mean you “remove” Nick from his “container”?

Ada: Not really. I create a clone of Nick (scary thought) and drag the clone to our meeting.

Nick: I am not sure I like that. Wait! If there are two of me, we both can bug you two.

Ada: In that case, I am going to use take that clone and put him back in the house at his address. That should cancel the extra Nick out.

Alan: Not really. When you do that, you actually create a second clone, and that means there are three Nicks moving around.

Ada: Ouch!

Nick: Why are all those students running away from that class over there?

Ada: Which students are you talking about?

Alan: The ones he is “pointing” to! They must be learning about “pointers”

Ada: I get it! Yuk, yuk!

Don’t panic, we will be doing very little with these pointers!)

Wires

In our Let’s Dance lecture, and the game we played in class, you got a first look at how electricity “flows” over a wire. At any point in time, the wire carries some voltage. That voltage is a measure of how many free electrons are in the wire. As we saw in class, it takes some time for these electrons to move around, but we can get away with ignoring that, as long as we keep our simulated wires short. (What does that even mean? We will get to that!)

Our view of a wire can be very simple. It is just a place that holds a single voltage at any given point in time. That value can change over time, but the voltage exists at every physical point in the wire. If we put a signal at one end of the wire, it is effectively available at the other end of the wire instantaneously!. We know that is not true, but the time involved is so short, we can ignore it.

That greatly simplifies out simulation of a wire. It becomes nothing more than a simple variable. (Well, a variable wrapped up in a class, so we can work with that variable - er – attribute! We will place a value in that variable, representing the signal we want to move.

Wires do nothing to the signal placed on them. They do not modify that signal in any way. Their purpose is simply to let that signal travel from one place in our collection of components to another place.

Watching Wires

Wires do play a very important role in a real electronic system, and in our simulated system. We are not allowed to look inside those “Black Box” components in a real computer, so we really should not look inside our simulated components either. To watch what is happening in our simulation as time progresses, we can watch what happens on the wires. In fact, this is how real electronics engineers work.

There is a neat gadget called an oscilloscope that can be attached to any wire in a system. As the system runs (over time) the oscilloscope`` will display the voltage on that wire. The display you can get might look like this:

../_images/digital-oscilloscope.jpg

Since we seem to be “simulating” everything else in out simulated computer, we will just build a simulated oscilloscope as well. That will require a bit of graphics work, and I am going to simplify that by using Python. I will provide the basic code for that!

We are just about ready to start our code. We need to summarize a few key concepts!

Connecting Wires to Components

Here is where those ugly pointers come in. We will “attach” a component to a wire using pointers. The component will need to maintain an internal pointer variable we can use to attach each wire. When the component action is triggered, the component will use the input pointer to reach out to the attached wire, whose address we store in that pointer variable``. It will then “read” the value of the current signal on that wire. When it is finished generating the output signals it will use the output pointer variables to “reach out” and place an output signal on the associated wire. We need to make sure that every component gets a chance to do part of the “dance”.

Writing the Simulator

We have enough of an idea about what we have to do, to start writing our simulator. As we create our code, always remember that one component cannot ever “call” another component. All objects just sit there until some event triggers them into action.

Huh?

Your component class may have a few variables, but they will be private. (They really should be, anyway!) The outside world cannot see them. There may be methods as well. Almost every one of those will also be private. The component can do some internal work, but the trigger event that starts the action will not be just any other another component “calling” a method. Instead, we will create one special component in our simulated system, whose purpose is to activate every other component in our simulated system. We will call that special component the clock, and it will call one method every component provides. Just for run, we will name that method tick.

Are you ready to see some code. That will be the next lecture in this series.