Introduction
This is general documentation for my MIPS emulator written in Python.
Goals
- Cross-platform
- Minimal binary size
- Make debugging the MIPS assembly language easier than what QtSpim offers
- Minimal dependencies
Limitations
- A minimal emulator for the MIPS assembly language that uses the University of Saskatchewan's CMPT 215, class as a baseline for what features are supported
Installation
Prerequisites
- Have Python 3.10 or higher installed
- Have pip3 installed
Installing dependencies
while you are in the root of your project run:
pip3 install -r requirements.txt
NOTE: on some installations it is simply pip, while others use pip3
Currently there are only three dependencies:
pyQt5
termcolor
toml
This project could probably do without termcolor but, for now, it is fine as it is.
Usage
Running the emulator
Now you can simply run the main.py file with the path to an assembly file as an argument
python3 main.py <path_to_assembly_file>
or alterantively you can complile the python files into a c executable binary, this is useful if you want the emulator
to be available as a shell command by moving it to ~/.local/bin
or any other executable path
Compiling and running the emulator
To compile the emulator, first enssure that you can run the make
command then simply run,
make build
this will compile a binary in the dist/
subdiretory of the project
to run the emulator simply ./dist/PyMIPS <path_to_assembly_file>
Configuration file
The Configuration file is pymips.toml
Features
key | values | description |
---|---|---|
register_base | bin dec hex | the numerical base all registers display in, under the hood it's still decimal |
memory_mapped | true false | enable or disable memory mapped registers |
end_of_instruction | true false | enable or disable end of instruction |
Runner
key | values | description |
---|---|---|
entry_point | label name | the label which executes at the start of the program |
file_to_run | path | the path to the assembly file to run |
Debugger
key | values | description |
---|---|---|
breakpoints | list of line number(s) | a list of line numbers to break at |
watchpoints | list of expression(s) | a list of expressions to watch |
Architecture
main.py
This is the main entry point for the entire program
Taking in arguments
We take in two inputs using the stdlib's argparse module, the first argument is a path to the assembly file that
you want to run, this does not check for the validity of the .asm
or .s
file, which is you could conceivably
load a python file or a simple text file, and only the pre-processor might throw an error, if not then the interpreter
will further downstream. The --no-gui
arg can be passed to disable the GUI and just run the Interpreter.
Setting things up
Setup, the IDE and colour palette (dark theme). We also set up an exception hook, this exception hook allows us to catch our custom defined exceptions in exceptions.py and catch them to act appropriately, like catching an exit code or RecursionError.
This however still allows us to continue on general Python exceptions, which are handled by PyQt.
exceptions.py
There is a general base/ parent class for all custom exceptions called InterpreterException which inherits from the in-built Exception class. This class is an abstract class cannot be instantiated on its own, you need to instantiate one of it's many subclasses.
The InterpreterException class takes in a message that will be displayed to the user upon encountering the exception,
it can also take in three optional keyword arguments: label_that_crashed
, instruction_that_crashed
and exit_code
.
Interpreter Exceptions
Name | Description | Example |
---|---|---|
InterpreterSyntaxError | when a syntax error is encountered in the assembly code | an empty label or out of place label |
InterpreterProcessError | when functions are called out of the expected order | the Interpreter is run before the labels and memory is mapped |
InterpreterRegisterError | when an invalid register is used | some value is set to register $t55 |
InterpreterControlFlowError | when an unexpected control flow event occurs | the code has reached someplace it shouldn't, processing a jump instruction from the Multiplexer |
InterpreterValueError | ||
InterpreterConversionError | an invalid conversion took place | |
InterpreterRuntimeError | a general runtime exception | |
InterpreterInstructionError | an instruction is encountered that is not valid | an invalid instruction xyz is encountered |