CS 595: Project 1: Hawknest 6502v Emulator

Overview

For this project, you will be completing the implementation of the Hawknest emulator. This emulator will be built around the 6502v processor, a version of the MOS 6502 CPU which I've modified slightly for our convenience. The v indicates that this CPU supports paravirtual extensions (namely, a new instruction).

The goals of this project are to:

Keep in mind that this is an experimental project, and it is the first time that it is being offered. If we encounter bugs or hiccups, we will work through them together.

Part 1: Getting Started

You will first need to download the Hawknest skeleton code. We will be working primarily with git, so make sure you are familiar with it and that you have it installed on your system. I would recommend working on this project either on a Linux machine or a Linux VM, ideally something you have sufficient permissions on to install software packages. To get the code, run the following in your VM:

    
    $> git clone http://cs.iit.edu/~khale/class/vm-class/f17/hawknest-skeleton
    
    
This will fetch the code from a public git repo. You should see something like this:
    
    $> cd hawknest-skeleton
    $> ls
    Makefile   README.md  cfg/       depend.sh* fonts/     include/   src/
    test/
    
    
If you try to build the project at this point, it will likely fail because you haven't installed the requisite libraries. See the next section for how to proceed.

Part 2: Building and Running Hawknest

This section will get you to the point where you can build and run the Hawknest emulator.

Prerequisites

Before we build Hawknest, we need to make sure that we have the required graphics libraries installed on the system. These include:

All of these can be installed using your distro's package manager. For example, I'm on a Fedora system so I would use the dnf package manager to install them as follows:
    
    $> sudo dnf install mesa-libGL SDL2 SDL2-devel SDL2_ttf SDL2_ttf-devel
    
    
Here, mesa-libGL is the OpenGL package. The rest are for SDL (a graphics library). Make sure to get the SDL version 2 packages, as version 1 will not work for us.

Building the Emulator

Once you have installed the prerequisites, you should be able to build the emulator as follows:

    
    $> make
	src/main.o <- src/main.c                      
	src/sys.o <- src/sys.c 
	src/memctrl.o <- src/memctrl.c                
	src/cartrom.o <- src/cartrom.c                
	src/sysrom.o <- src/sysrom.c                  
	src/io.o <- src/io.c   
	src/shell.o <- src/shell.c                    
	src/mos6502/cpu.o <- src/mos6502/cpu.c        
	src/mos6502/vmcall.o <- src/mos6502/vmcall.c  
	src/gui/gui.o <- src/gui/gui.c                
	src/dev/controller.o <- src/dev/controller.c  
	Linking...[hawknest <- src/main.o]
    
    
You should now have a binary called hawknestin the main directory. If you run it without any arguments (or with the -h flag), you will get a help message.
    
    $> ./hawknest
    
    

Building ROMs (test code)

I've supplied you with a simple test program in the test/ directory in the main source tree. There is a C file called test.c and a 6502 assembly file called testwrite.s which tests a file writing routine. If you look at the Makefilein that directory, you can see how this is built in the same way as the code in your preliminary project, but using a library called hawknest.lib and using a special linker script called hawknest.cfg. If you want to add your own tests, a good idea is to just add them to that Makefile and put the source in the test directory.

When you compile this testcode by running make, you'll notice that two files are produced. One is the cartridge ROM (in this case called testsuite and the other is the System ROM binary image (here called testsuite-sysrom.bin. You'll need both of these for any program you compile for Hawknest, and as long as you compile in the same way as is dictated in the Makefile, the compiler will automatically produce both.

Running Hawknest

Once you have your two ROM files, you can run them in Hawknest. For example, with the ROM files above, we could run like this:

    
    $> ./hawknest -c test/testsuite -s test/testsuite-sysrom.bin 
    
    
This will run Hawknest in graphical mode by default. Notice that nothing happens. This is because there's no CPU to run the program! You will implement this, and when you do, you'll start to see some output here. You can slo run Hawknest in an interactive shell, which is more useful for debugging purposes:
    
    $> ./hawknest -i -c test/testsuite -s test/testsuite-sysrom.bin 
    
    
Again, here you can type commands into the interactive shell, but aside from the memory peek, poke, and dump commands, they won't do anything. The memory commands will work just fine since I've already implemented the memory controller, RAM, and ROM subsystems for you.

While working on your project, you may want to have debugging prints that only appear when you are debugging your CPU. I've provided a macro for you to achieve this. The macro is called DEBUG_PRINT. You should use it just like you would printf, but it will only produce output when the code is compiled for debugging. To compile with debug output enabled, open the file .config in your editor and change the line DEBUG_ENABLE to 1.

Part 3: Implementation

This section will outline some strategies for building your 6502v and how to write readable code.

Strategy

Before getting started writing code, I would recommend that you spend some time getting familiar with the codebase. I've already given a few high level overviews of how the system works, so you should have a vague idea at this point. The very first piece of code that is executed is in src/main.c. This code parses arguments and calls the system initialization routine, at which point we're off to the races. In src/sys.c you'll see calls to routines which you will implement, e.g. mos6502_init() and mos6502_step(). Unless you're curious, I wouldn't spend too much time worrying about the graphics code or the controller code, as we won't be dealing with that until later.

When getting started, the first priority is to get your CPU initialized (reset) and executing instructions. See the my comment at the top of cpu.c for more instructions on how you should proceed. Note that I've given you some of the function definitions you'll need (primarily the ones that will be called by other code), and you'll need to fill them in.

Suggested Tools

When navigating and working with a large codebase, there are several tools you might want to get familiar with. The first is ctags. This is a utility which creates an index of all the functions and symbols in your source tree, which you can then use to navigate easily within a text editor like vi.

For example, to use ctags for this project, in the Hawknest directory, run the following (you may have to install the ctags package):

    
    $> ctags -R
    
    
This will create a tags file in this directory. To use this in vi or vim, add the following line to your .vimrc file in your home directory:
    
    tags=tags;/
    
    
Now, within vi or vim, if you hover over a symbol that you want to see the definition of, e.g. a function, you can navigate to it simply by pressing ctrl + ]. You can go back to where you were before by typing ctrl + t. Emacs has similar capabilities.

Other tools that might be useful:

Updates

As we progress on this project, I will likely be making updates to the sections of code that you are not working on (e.g. graphics code, interrupt handling, libraries etc.). If I do make updates, I will ask you to get them from the repo using:

    
    $> git pull
    
    
Because of this, I would advise against adding code to parts of the system outside of cpu.c unless absolutely necessary.

Handin

Once you're convinced that your 6502v is complete, you will handin your code as a git patch or as a set of git patches. In order for this to work, you want to commit changes to your code in logical chunks as you go. DO NOT just hand me one big commit containing all your code. Your commits should be clearly described with a log message, and should clearly show authorship. Here is how I make a commit.

    
    ...add stuff to git index using git add...
    $> git commit --author="Kyle Hale <khale@cs.iit.edu>"
    
    
Then include a desriptive line such as "Added implementation of JMP instruction."

When you're finished, you can turn your commits into patches using git format-patch. This will produce several .patch files which you should be able to group into a tarball which you can then send to me directly.

Note that the due date for this assignment is October 13 at 11:59PM.