Abstract
Our Python-based MIPS simulator provides a platform for simulating the execution of MIPS binary code
generated by external assemblers such as MARS. The simulator includes a processor and a compiler that
can handle binary code, allowing users to write, compile, and execute MIPS programs within the simulated
environment.
Our simulator mimics the MIPS architecture using key components like the Program Counter (PC), Instruc-
tion Memory (IM), Register File (RF), Data Memory (DM), Arithmetic Logic Unit (ALU), and Control Unit
We’ve created a user-friendly MIPS simulation environment where users can work with MIPS binary code.
We’ve included sample programs in the simulator, covering arithmetic, control flow, memory access, and
data manipulation tasks. These programs showcase MIPS architecture in action and can be run smoothly within
Our simulator supports the simulation of MIPS binary code, allowing users to experiment with code gen-
erated by external tools. This feature enables users to explore MIPS programming concepts in a controlled
The MIPS simulator is built with different parts that are separate but work together. The main part, known
as the central processing unit (CPU), manages how instructions are carried out by coordinating with other
- The Program Counter (PC) keeps track of which instruction is being worked on.
- The Instruction Memory (IM) stores all the instructions to be executed by the processor.
- The Register File (RF) contains several registers where data and temporary results are stored during
- The Data Memory (DM) serves as the computer’s main memory, storing data.
- The Arithmetic Logic Unit (ALU) performs mathematical and logical operations on data.
- The Control Unit (CU) reads instructions from the Instruction Memory and directs the other components
By having these components work together, our MIPS simulator functions like a real MIPS processor. It
The Program Counter (PC) keeps track of the memory address of the current instruction being executed
and controls the flow of instructions. It is responsible for updating the address of the next instruction based on
class PC:
def __init__(self , value):
self.value = value
self.pcSrc = 0
self.jump = 0
def update(self , address , branchAddress):
if not self.jump:
if (self.pcSrc != 0):
print(’pc is branching ’)
self.value = self.value + 4 + branchAddress
print(’pc is now’, self.value)
else:
self.value += 4
else:
self.value = address << 2
In the above implementation, thePCclass maintains the current value of the program counter and provides
In MIPS architecture, memory is byte-addressable, meaning that each byte in memory has a unique address.
Instructions in MIPS are typically stored as 32-bit words. Each word consists of 4 bytes. This byte-
addressable nature of memory facilitates precise control over data and instructions at the byte level, enabling
The instruction memory (IM) in our simulator works with byte-addressable memory for storing instructions.
1 class IM: 2 def init(self): 3 # Initialize instruction memory array with 0s 4 self.mem = [0] * 0xffc 5 print(’Initialized Instruction Memory ’) 6 self.RD = 0 7 8 def RDPort(self , A): 9 # Read 4 bytes (32 bits) from memory to form an instruction 10 self.RD = int( 11 num_to_8bit_binary(self.mem[A + 3]) + 12 num_to_8bit_binary(self.mem[A + 2]) + 13 num_to_8bit_binary(self.mem[A + 1]) + num_to_8bit_binary(self.mem[A]), 14 2) 15 print(’Instruction fetched from memory: ’, self.RD) 16 return
The memory is organized so that each element in thememarray represents a byte of memory. When fetching
instructions, we access 4 bytes (32 bits) at a time to form a single instruction word. This allows us to effectively
By utilizing byte-addressable memory and accessing instructions as 32-bit words, our simulator accurately
1 class RF:
2 def __init__(self):
3 self.WE3 = 0
4 self.RD1 = 0
5 self.RD2 = 0
6 self.file = [0] * 32
7 self.file [29] = 16380 # stack pointer location in DM
8 self.RegDst = 0
9 self.MemtoReg = 0
1 def RD1Port(self , A1):
2 self.RD1 = self.file[A1]
3
4 def RD2Port(self , A2):
5 self.RD2 = self.file[A2]
1 def WD3Port(self , rt , rd , ALUResult , RD): 2 if (self.MemtoReg == 0): 3 value = ALUResult 4 elif (self.MemtoReg == 1): 5 value = RD 6 if (self.WE3): 7 if (self.RegDst == 0): 8 self.file[rt] = value 9 elif (self.RegDst == 1): 10 self.file[rd] = value
In this part, we take a closer look at how the processor works when it runs programs and handles data in
its memory. We’ll focus on two key parts: the Control Unit (CU) and the Arithmetic Logic Unit (ALU). These
parts are like the brain and muscles of the processor, working together to process instructions and manage
The Control Unit (CU) manages control signals and sets them based on the opcode and function code of
1 class CU: 2 def init(self , RF , DM , ALU , PC): 3 self.ALUControl = 0 4 self.RF = RF 5 self.DM = DM 6 self.ALU = ALU 7 self.PC = PC 8 self.branch = 0 9 10 def set_signals(self , opcode , funct): 11 #set signal to different select lines 12 ...
fromMachine.outinto memory. Additionally, specific memory locations are initialized to set the stage for
The ALU, short for Arithmetic Logic Unit, is a fundamental component of the processor responsible for
1 class ALU: 2 def init(self): 3 self.ALUResult = 0 4 self.Zero = 0 5 self.Control = 0 6 self.ALUSrc = 0 7 self.srcA = 0 8 self.srcB = 0 9 10 def calculate(self , srcA , rtVal , imm): 11 # Source Decision 12 self.srcA = srcA 13 if (self.ALUSrc == 0): 14 self.srcB = rtVal 15 elif (self.ALUSrc == 1): 16 self.srcB = imm 17 else: 18 self.srcB = 0 19 self.Zero = self.srcA - self.srcB 20 21 # ALU operation 22 if self.Control == -2: 23 self.ALUResult = self.srcA * self.srcB 24 if self.Control == 0b010: 25 self.ALUResult = self.srcA + self.srcB 26 elif self.Control == 0b110: 27 self.ALUResult = self.srcA - self.srcB 28 elif self.Control == 0b101: 29 self.ALUResult = self.srcA * self.srcB 30 elif self.Control == 0b000: 31 self.ALUResult = self.srcA & self.srcB 32 elif self.Control == 0b001: 33 self.ALUResult = self.srcA | self.srcB 34 elif self.Control == 0b111: 35 if self.srcA < self.srcB: 36 self.ALUResult = 0b 37 else: 38 self.ALUResult = 0b 39 else: 40 pass
input data. It handles operations such as addition, subtraction, multiplication, bitwise AND, bitwise OR, and
- IfControlrepresents addition (0b010), the ALU addssrcAandsrcB.
- IfControlrepresents subtraction (0b110), the ALU subtractssrcBfromsrcA.
The ALU’s versatility and efficiency make it a vital component of modern processors, enabling them to
program, descending bubble sort and finally, a recursive factorial code that utilizes stack pointers. Note to be
taken that ’mul’ was implemented as an R-type instruction as MARS supports it without any pseudo instruction
(according to MARS, it has a valid 32-bit instruction)Also, MARS memory was configured to have .text
1 .text 2 .globl main 3 4 main: 5 # Array initialization 6 li $t0 , 1 # Load first array element 7 li $t1 , 2 # Load second array element 8 li $t2 , 3 # Load third array element 9 li $t3 , 4 # Load fourth array element 10 li $t4 , 5 # Load fifth array element 11 12 # Calculate sum 13 add $s0 , $t0 , $t1 # Add first and second element 14 add $s0 , $s0 , $t2 # Add third element 15 add $s0 , $s0 , $t3 # Add fourth element 16 add $s0 , $s0 , $t4 # Add fifth element 17 18 # Print sum 19 li $v0 , 1 # Load system call code for printing integer 20 move $a0 , $s0 # Move sum to argument register 21 syscall # Perform system call to print sum 22 23 # Exit program 24 li $v0 , 10 # Load system call code for program exit 25 syscall # Perform system call to exit program
First array element: 1, Second array element: 2, Third array element: 3, Fourth array element: 4, Fifth
We present an implementation of a bubble sort program in MIPS assembly language. The program sorts an
1 .text 2 .globl main 3 main: 4 # Load array base address 5 addi $s0 ,$zero , 0x 6 # Load array size (4 times the number of elements in the array) 7 addi $s1 , $zero , 40 8 addi $t0 , $zero , 10 9 sw $t0 , 0($s0) 10 addi $t0 , $zero , 2 11 sw $t0 , 4($s0) 12 13 addi $t0 , $zero , 5 14 sw $t0 , 8($s0) 15 16 ... # Rest of the array initialization 17 jal bubble_sort 18 # Exit program 19 addi $v0 ,$zero , 10 # syscall code for exit 20 syscall 21 22 bubble_sort: 23 addi $t0 , $zero , 0 # i = 0 24 outer_loop: 25 sub $t6 , $s1 , $t0 # t6 = n - i 26 addi $t6 , $t6 , -4 # t6 = n - i - 4 27 beq $t6 , $zero , end_bubble # if n - i == 4, exit outer loop 28 29 addi $t1 , $zero , 0 # j = 0 30 inner_loop: 31 beq $t1 , $t6 , next_outer # if j == n - i - 4, go to next outer iteration 32 33 # Load arr[j] into $t 34 add $t7 , $s0 , $t1 # base address + offset 35 lw $t2 , 0($t7) 36 # Load arr[j+1] into $t 37 addi $t8 , $t1 , 4 # j + 4 38 add $t8 , $s0 , $t8 # base address + offset 39 lw $t3 , 0($t8) 40 41 # Compare arr[j] and arr[j+1] 42 slt $at , $t2 , $t 43 beq $at , $zero , no_swap 44 45 # Swap arr[j] and arr[j+1] 46 sw $t3 , 0($t7) 47 sw $t2 , 0($t8) 48 49 no_swap: 50 addi $t1 , $t1 , 4 # j += 4 (increment by word size) 51 j inner_loop 52 53 next_outer: 54 addi $t0 , $t0 , 4 # i += 4 (increment by word size) 55 j outer_loop 56 57 end_bubble: 58 jr $ra # return to caller
First array element: 10, Second array element: 2, Third array element: 5, Fourth array element: 4, Fifth
array element: 3, Sixth array element: 6, Seventh array element: 7, Eighth array element: 8, Ninth array
1 .text 2 addi $t1 , $zero , 1 3 addi $a0 , $zero , 6 4 jal fact 5 add $s0 , $zero , $v 6 addi $v0 , $zero , 10 7 syscall 8 fact: 9 addi $sp , $sp , - 10 sw $ra , 4($sp) 11 sw $a0 , 0($sp) 12 slt $t0 , $a0 , $t 13 beq $t0 , $zero , L 14 addi $v0 , $zero , 1 15 addi $sp , $sp , 8 16 jr $ra 17 L1: 18 addi $a0 , $a0 , - 19 jal fact 20 lw $a0 , 0($sp) 21 lw $ra , 4($sp) 22 addi $sp , $sp , 8 23 mul $v0 , $a0 , $v 24 jr $ra