Emulator

This project implementats of a very simple processor to execute instructions.

CPU Overview

The CPU being emulated uses a custom 32-bit architecture. Instructions are all 32 bits in length. Data words in registers are also 32 bits in length.

The following registers are available:

  • R0 - General data register
  • R1 - General data register
  • R2 - General data register
  • R3 - General data register
  • R4 - General data register
  • IP - Instruction pointer (Points to the next instruction to execute)
  • IR - Instruction register (holds the current instruction)

Instruction Format

Instructions are all 4 bytes. Each byte represents the following:

Byte 0 Byte 1 Byte 2 Byte 3
op dst src immediate
  • op - Operation to execute
  • dst - Destination register
  • src - Source register
  • immediate - Immediate Value (signed)

Specifically, instructions can be represented using the following struct:

typedef struct {
  Operation op;
  Register dst;
  Register src;
  signed char immediate;
} Instruction;

Operations

This simple processor supports the following operations:

  1. Halt - Stop the processor
  2. LoadImmediate - Store the value in immediate to register dst.
  3. Add - Add the value from register src to the value in register dst and store the result in dst.
  4. AddImmediate - Add the value in immediate to register src and store the result in register dst.
  5. And - Bitwise and the value from register src to the value in register dst and store the result in dst.
  6. Or - Bitwise or the value from register src to the value in register dst and store the result in dst.
  7. Xor - Bitwise xor the value from register src to the value in register dst and store the result in dst.
  8. Jump - Jump to the absolute position stored in the immediate value.
  9. BranchOnEqual - Jump to the absolute position stored in the immediate value if and only if the values in the src and dst registers are equal.
  10. LoadDirect - Load the value stored in the memory location pointed to by immediate into the dst register.
  11. StoreDirect - Store the value stored in register src into the memory location pointed to by the immediate value.
  12. LoadIndirect - Load the value stored in the memory location pointed to by the value in src into the dst register.
  13. StoreIndirect - Store the value stored in register src into the memory location pointed to by the value stored in dst.

Assembler Overview

An assembler translates assembly language code to machine code. Your task is to update your CPU emulator to include an complete assembler by completing the assembler.c file. There are a few TODO comments that must be taken care of. You should be able to convert the included test-program.asm to machine code and execute it correctly.

Fibonacci

Once you have a working assembler, you should create a working assembly language program to calculate the nth Fibonacci number that your emulator is able to execute. More details can be found in the fibonacci.asm file. Both files can be assembled, executed, and tested by simply calling make.

Running

The emulator can be compiled and tested by invoking:

make

Debugging Tips

A couple of tools are provided to make debugging easier.

  1. print_instruction can be used to pretty print an instruction. For example:
// Print the instruction stored in `inst`
print_instruction(inst);
  1. print_registers can pretty print register values. For example:
// Print the current register values stored in `registers`:
print_registers(registers);
  1. TEST_CLOCK can be modified to adjust the clock speed of the CPU during testing. The emulator defaults to a 1 MHz CPU, but it may be helpful to run it much, much slower whole observing instruction and register values.

  2. printf can be used to print any values of interest.