COMSC-221 Fall 2025
Lab 10: MIPS Single Cycle Simulator
Putting it All Together
Do not download the code associated with this lab if you have not yet completed any
one of the previous simulator labs. To do so is a violation of the honor code.
Once this lab has been downloaded, do not share any of the code with anyone other
than your partners and do not post the code in any public location (e.g. GitHub). To
do so is a violation of the honor code.
In this lab, you will write the code necessary to complete the MIPS processor simulator.
You will use the code you write for this lab, along with the components from the previous
labs to simulate the actions of a single cycle MIPS processor. We will provide working
versions of previous related labs so that everyone begins this lab with the same materials
and starter code.
We’ve said this before, but it is still very true… This lab will be significantly easier overall
and less work for each individual group member if you carefully READ THROUGH THIS
ENTIRE DOCUMENT BEFORE YOU WRITE ANY CODE!
Part 0: Planning
Before you look at the starter code, review the fetch-execution cycle and clarify which individual
tasks are performed in each step of instruction execution. Remember that the text goes over this in
detail as do the videos and slides.
Write up an outline for each step of the fetch-execution cycle that lists all subtasks that take
place during that portion of the cycle.
Part 1: Setup
You will receive an email with the starter code for this lab once your group has submitted Lab 9.
Download the starter code from the email, then untar it. Verify that the resulting Lab10_Starter
directory it creates contains the following:
1. Execute: contains files for completing the simulator.
***These are the only files to which you should make any changes.***
a. MIPSsim.c
b. control.c
c. control.h
d. makefile
2. CompletedCode: contains completed code for the previous programming assignments.
***Do not make any changes to these files.***
a. alu.h
b. alu.c
c. dataMemory.h
d. dataMemory.c
e. instructionMemory.h
f. instructionMemory.c
g. registers.h
h. registers.c
3. TestProgs: contains paired input files. These files should be used to test your completed
simulator.
a. alutest – instruction memory input file for testing ALU operations
b. alutest.dat – data memory input file for alutest program
c. jumptest – instruction memory input file to test that jump works correctly
d. jumptest.dat – data memory input file for jumptest program
e. multiply – instruction memory input file for testing branch and jump
f. multiply.dat – data memory input file for multiply program
Once you have verified that you have all the files listed above, be sure to do the following:
1. Copy all starter code to the following location on Rhea (you will need to first create the
Lab10 directory):
~/shared/COMSC221/Lab10
2. Move all the source and header files from CompletedCode and the input files from
TestProgs into the Execute directory so that you can more easily test your code as you
write it.
3. Perform a make to verify that you have all the files you need to compile the program.
Part 2: Coding
Once again… DO NOT look at the starter code if you have not completed and submitted all
of the previous simulator labs.
Before you start coding, compare your fetch-execute cycle outline from Part 0 to the functions
available in the starter code. Which existing functions will help you carry out the steps you
outlined? Looking at the diagrams in Appendix A, try to figure out how it all fits together. Trust us…
Taking the time to do this now will save you a huge amount of time when it comes to actually
writing and testing the code.
***Reminder: control.c, control.h, and MIPSsim.c are the only files you should modify for this lab.
The source and header files for registers, dataMemory, instructionMemory, and alu should stay
exactly the same.***
Complete the public functions of control.c
● executeInstruction
● getPC
● setPC
1. The most important function, executeInstruction, executes the MIPS instruction whose
address is in the PC.
2. Use your outline of the fetch-execution cycle to plan your code. Your simulator should run by
executing one instruction at a time. executeInstruction should carry out the execution of an
instruction. It should do this by performing the five stages/steps of the execution cycle as
you outlined.
3. Write helper functions so that your code will be easier to read and to debug! We can’t
stress enough how important this is. The helper functions must not be public, so declare
them as static. It would be helpful to use abstraction here to control the complexity of
writing this section. More specifically, think of each step of the cycle independently and
write a function to perform each one, writing helper functions for these as it makes sense
to do so. Note that the solution code for the other components has examples of static helper
functions which may help you to think about how to structure the code you write.
4. You should only access the instruction memory, data memory, registers, and ALU from
control.c using the functions that were written previously in dataMemory.c,
instructionMemory.c, registers.c, ALU.c. This is where all those setters and getters you
wrote in the previous labs will be useful. If you don’t think you can gain access to some
value or component you need with the existing functions, there is something wrong with
your plan.
5. Do not use any form of conditional that checks for the type or opcode of the
instruction. Your code should simulate the processes that the datapath performs based
entirely upon the control signals at each stage of execution. For example, during the
memory stage, if MemRead = 1 then memData should get the value of the read data from
data memory.
6. Your simulator should be able to handle the following instructions: lw, sw, add, sub, and,
or, slt, beq, and j.
a. The jump instruction has not yet been implemented, so you will need to modify your
code to enable jumps. Take a look at the diagram in Appendix A showing you which
parts of the datapath actually get used for a jump instruction. Allow that to guide you
when thinking about when to check whether this is a jump instruction or not. (HINT -
It’s pretty early, and none of the other stages need to happen once you know you’re
executing a jump)
b. Also note that there is an additional control signal called Halt. The purpose of this
signal is to keep track of when a halt instruction has been decoded (recall that we
don’t know what instruction we have until we have decoded it). Since a Halt in our
simulator will be 0xffffffff and opcodes consist of 6 bits, the opcode for a Halt will be
0x3F or 6310. You will need to modify your code to set the value of Halt when the
other control signals are set. If a halt instruction has been decoded, set Halt =1,
otherwise Halt = 0. When Halt = 1, no further execution of the halt instruction or
any other instruction should occur. (HINT - Halt should be implemented as
described here. If you go online and search for information on “halt signals”, what you
find will probably make your life harder and possibly take you in the wrong direction
entirely.)
Write a main program in MIPSsim.c that takes five command line arguments
Those arguments are:
● The name of the executable file (MIPSsim)
● The name of the file for initializing the instruction memory.
● The number of instructions to be read in.
● The name of the file for initializing the data memory.
● The number of data items to be read.
Remember that in the main function, argc indicates the number of arguments and argv will be an
array containing those arguments. If you have your main set up correctly, here is an example of a
command that would test it on one of the available testing sets:
./MIPSsim alutest 11 alutest.dat 2
Note that there is one space between each argument. Assuming your code works and has been
properly compiled, this would start MIPSsim and test it using the first 11 instructions from alutest
and the first 2 data items from alutest.dat.
The main program should do the following:
1. Initialize the instruction memory using a filename passed on the command line and the
number of instructions to read.
2. Initialize the data memory using a filename passed on the command line and the number of
data items to read.
3. In a loop, output a menu with the following choices in it:
a. Execute the next n instructions
■ Call executeInstruction up to n times, provided there is an instruction to
execute
b. Dump data memory
■ Call dumpDataMemory
c. Dump registers
■ Call displayRegisters
d. Quit
■ Exit the program
4. The simulator should continue to run until the user selects quit.
Part 3: Testing
To test using the GDB GUI debugger (highly recommended!), you will need to run the program in a
slightly different way because of the command line arguments. Be sure you compile using make,
then start up the debugger using the command:
gdbgui MIPSsim
Once you have the debugger open and have set a breakpoint, don’t run the program using the play
button. Instead, go to the lower left panel which should have the (gdb) prompt and enter run
followed by the additional arguments. So, for instance, if you wanted to test using the alutest
program in the debugger, you would type the following next to the (gdb) prompt:
run alutest 11 alutest.dat 2
Each file in the TestProgs directory contains comments so you can check the simulator’s register
and memory values as the program executes to be sure it is doing what it should. For each pair,
one file contains the program instructions for your simulator to execute and one file contains the
data for that program.
The format is such that each instruction or data item is on a single line, followed by comments
preceded by the ‘!’ symbol. When your program reads the file, it should save the instruction, but
ignore the comments.
One way to do this is to read the file one line at a time using fgets and process each line as it’s
read. Use sscanf to read the hex value from the string storing the current line. Here is an example
line from an instruction file:
0x8c010000 ! 0: lw %1, 0(%0) 100011 00000 00001 0000000000000000; r1<= 12
Comments after the ‘!’ explain what each instruction does, which registers and/or immediate values
are used, and how registers/memory are modified. Use the comments to check that your simulator
is working correctly. Note that every program ends with a Halt instruction.
Submission
Be sure the names of all group members are in comments at the top of each file you have
modified!
Submit all of your files untarred on Gradescope. Your submission should contain:
1. control.c
2. control.h
3. MIPSsim.c
4. registers.c
5. registers.h
6. dataMemory.c
7. dataMemory.h
8. instructionMemory.c
9. instructionMemory.h
10.alu.c
11.alu.h
12.makefile
Submissions for this lab are due Thursday, November 20 at 11:50pm
Grading
control.c 40
halt implementation 5
jump instruction implementation 5
MIPSsim.c 15
UI/Testing implementation 5
Total 70
Appendix A: MIPS CPU Diagrams
Datapath Broken Into Steps (control and jump not shown)
Datapath with Control (jump not shown)
Datapath for Jump Instructions