Building a Simulator

Read time: 35 minutes (8950 words)

We are now in a position to begin serious work on a simulator. I am going to model this simulator on the smallest microcontroller I happen to own now, the Atmel attiny85. We will not be able to build a complete simulator for this tiny chip, but we will use it for inspiration. The project you will work on will consist of several steps and the lecture notes will guide you through them.


You might be tempted to just copy-and-paste example code to complete this work. Do not do that. All copy-and-paste teaches you is how to copy-and-paste. I am keeping these steps small so you understand what we are doing. Nothing bets running example code after you study it a bit. YMMY!

We Need to “Git” More Power

So far, we have been using Git in a very basic way. We learned a simple “mantra” and we develop the way we have always developed. (OK, the command line is probably different!) It almost seems like Git simply adds work for us to do, in the form of additional commands to learn.

That is true, but if you look at how you are developing now, you are using in a much safer workflow. GitHub is acting like your project backup system. If you ever make a huge mistake on your project, you can throw the entire thing away, and start over, by cloning the previous version safely stored on GitHub. Or, you can sit down in front of a completely different machine, “clone” your project from your GitHub account, and continue work on your project (as long as your development tools are installed!)

All of these new capabilities are good, but we have not tapped the real power of Git, the ability to move backward in time to previous versions. We will explore that capability as we work through this project.

Let’s begin our new simulator project:

Step 1: Create the Project Directory

We start off by building a new project directory. Pay attention to the directory name we are going to use here!

$ cd ~/cosc2325     (assumes all class projects are in this directory)
$ cd cosc2325-projects-username
$ mkdir attiny85sim

We are going to call this project attiny85sim, not lab3. Project names really ought to help identify the project, not the assignment number!

Write Some Code

Next, we will add a variant of our classic “Hello World” application.


This should always the first step in beginning a new project! You should not sit down to a marathon typing (or copy-paste) session and mash together a bunch of code!

Here is our new code:

#include <iostream>

int main(void) {
    std::cout << "attiny85sim (v0.1.0)" << std::endl;

Make Sure It Runs

That was enough typing to check our work.

Let’s run this simple example!

$ g++ -o attiny85sim main.cpp
$ ./attiny85sim
attiny85sim (v0.1.0)

Too Much Typing!

That was way too many characters to type. Even with the easy access to the command history in the terminal (actually, bash is doing that), we still have to type in those long commands at least once.

Since programmer’s are lazy (and creative), surely someone addressed that problem.

They did, way back in 1976!

Introducing Make

The tool that they developed back then, written by Stuart Feldman (see this link), is known as Make, and the command you will learn to love is simply make!

Make is installed as part of the standard developer’s tool set on Mac/Linux, and can be added to any Windows system. Lets verify that we have it installed:


I write these notes on my Macbook, so what you see reflects my system:

$ make --version
GNU Make 3.81
Copyright (C) 2006  Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A

This program built for i386-apple-darwin11.3.0

The version of Make we will be using is the Gnu Make system. This is not the only such tool around, Microsoft has its own (they think better) version called nmake, which comes as part of Visual Studio. Since this tool is locked into the Windows world, I seldom use it!

Scene: Coffee shop

Ada: Why does Microsoft seem to want to change every standard tool into something they wrote instead?

Nick: It is called the “NIH syndrome”!

Ada: What is that?

Alan: “Not Invented Here”. Developers who did not write something are just SURE they could do it better, so they write something over from scratch.

Ada: That sounds like a good way to learn about something, but a huge waste of time if that something is sitting there, ready to use!

Nick: Exactly!

Alan: IBM once did a study and found out that their developers worldwide were wasting huge amounts of time writing code other IBM employees had already written. They build a database system to catalog their code and stopped that waste!

Nick: Developers are told to use the “DRY” principle: “Don’t Repeat Yourself”. Looks like that applies to corporations as well!


Make uses a single text file to control what it does. It is vital that you understand that Make is not a tool that really knows much about programming. Instead, Make looks at the relationships among a set of files, and issues commands for you, based on changes in those files.


Rather than get deeply into Make here, I will build up your understanding of this powerful tool by showing it in action, with simple examples. We will get more sophisticated in our use of Make as we proceed.

The one file we need to build so that Make can take control of our build process is called Makefile (or makefile).


Makefile does not have an extension, and it is a simple text file. There is one HUGE “gotcha” in writing these, though. The <TAB> character must be used in certain places. Watch for that!

Here is a first Makefile for our project:

.PHONY: all
	g++ -o attiny85sim main.cpp

.PHONY: run

.PHONY: clean
	rm -f attiny85sim

Those lines that begin with .PHONY: tell Make that it should not look for a file with that name in the project directory (where this Makefile is located). Actually, it will ignore such a file if it is there. More on that later!

The line below each of those “PHONY” lines is called a target. By default, the first such target will mark the place where Make begins looking for commands to run. You can have many targets in a makefile. Make will not run all of them, just those needed. This is what makes (!) it so powerful.


Target lines start with a name followed by a colon. The name can be the name of a file that Make is to build, or (if marked as .PHONY:) it might just be the name od some set of commends you want Make to run for you. There will be many such lines in a sypical Makefile. In our first example, all target lines are marked as .PHONY.

The actual command (or commands) we want Make to run for use begin on the next indented line. What you see there is something you could type, but do not want to!


Look closely at the indented line after a target name. The first character in that line absolutely MUST be a <TAB>! You can check that by moving the cursor with the arrow keys. If it hops to the beginning of the like when you move left, you are fine. If it steps by single spaces, Make will complain. In Vim I use <Ctrl-V><TAB> to insert a tab.

You can ask Make to run several commands in a row, by listing each one on a separate line, indenting each one with that evil <TAB> character.

Try this:

$ make
g++ -o attiny85sim main.cpp
$ make run
attiny85sim (v0.1.0)

Much better! We simply typed “make” and Make ran the command we specified for us. If we want to run a different target listed in our Makefile, we add the target name after “make”.


Be careful when adding commands to a Makefile. The commands can get very complex. If you ever want to see what Make will do, without actually running the commands, add -n after the command:

$ make clean -n
rm -f attiny85sim

If you check, attiny85sim is still present, since the command was not run by Make.

That last target is designed to eliminate anything we can rebuild later from the project directory. I always run that command before committing work with Git.

Commit this version

Time to get this code on GitHub!

Before we do that, we need to add one important file to this project:

Create this file at the top of your class project folder (or check it if it is already there):

# Executables

# C/C++

# Python

# Vim

# Mac

We do not want to add the attiny85sim executable file, since it is something we can build from the project source code.


Originally, I just added the executable name to the .gitignore file. Unfortunately, the executable file name happened to be the same as the project folder name (not really that uncommon). Git happily ignored the entire project folder. Not Good! The solution was to specify the executable name more completely. This is shown in the above example.

Now, do the standard “mantra”:

$ git add .
$ git commit -m "completed version 0.1.0"
$ git push origin master

Tag this Version

Git creates a very ugly “name” for each commit you create. Formally, it is called a “hash code”. This is a 40 character hexadecimal code string that uniquely identifies a particular version of your project. (The odds on two projects having the same hash code as too small to even think about!)

Here is an example, from my test simulator project:

$ git log --pretty=oneline
9bd42d2e7e2f523badbb4437c255d7954c603540 basic Hello, World app added

The problem with these ugly names is that it is impossible for humans to remember them. We can just use the first few characters from those names and Git will figure out what name we mean, but even that is not much help.

What we want to do is attach a more “human” name to a version. We can do that simply by asking Git to tag our commit.

Do this:

$ git tag v0.1.0

That places a special marker on the project at this point in time. We now have a name we can remember: v0.1.0. See Project Versions for more information on version numbers).

There is one problem with tags in Git. They are not automatically included when you push changes up to GitHub. To get your tags on GitHub, which you only need to do after creating a new tag, is run this command:

$ git push origin --tags

You can get a list of your current tags using this command:

$ git tag

Reviewing this Step

This is not much of a start, but it is a good start! We have also learned a few new development tricks! THe real simulator code comes next!