This article introduces the MIPS architecture and its assembly language from four aspects:
1. Types of Registers
2. Arithmetic and Addressing Instructions
3. Program Structure
4. System Calls
The tool required is: Mars 4.4
Download link:
http://courses.missouristate.edu/KenVollmar/mars/download.htm
1 Data Types
1. All MIPS instructions are 32 bits long
2. 1 byte = 8 bits, half-word = 2 bytes, word = 4 bytes
3. A character space = 1 byte
4. An integer = a word = 4 bytes
5. A single character is enclosed in single quotes, e.g., ‘b’
6. Strings are enclosed in double quotes, e.g., “A string”
2 Registers
1. MIPS has a total of 32 general-purpose registers
2. In assembly, register identifiers start with a $ sign
3. Registers can be referenced in two ways:
Directly using the corresponding register number, e.g., from $0 to $31
Using the corresponding register name, e.g., $t1, $sp (detailed names are in the table below)
4. The Lo and Hi registers are specifically used to store the results of multiplication and division
For these two, there is no direct addressing; access must be done through special instructions mfhi (“move from Hi”) and mflo (“move from Lo”)
5. The stack grows from high addresses to low addresses
3 Program Structure
1. Essentially, it consists of data declarations + plain text + program code (file extensions can be .s or .asm)
2. Data declarations can be placed after the code segment (it is also acceptable to place them before, which aligns better with high-level programming design habits)
Data Declarations:
1. The data segment starts with .data
2. After declaring variables, space is allocated in main memory
Code:
1. The code segment starts with .text
2. It consists of various instruction operations
3. The program entry point is marked by main: (this is the same everywhere)
4. Program termination is marked
Comments:
1. This is the comment symbol
2. The basic template for a MIPS program is as follows:
# Comment giving name of program and description of function# Description of the program's purpose and function (similar to high-level languages) # Template.s# Bare-bones outline of MIPS assembly language program
.data # variable declarations follow this line # Data variable declarations # ...
.text # instructions follow this line # Code segment
main: # indicates start of code (first instruction to execute) # Main program # ...
# End of program, leave a blank line afterwards to make SPIM happy# Must leave you one more line, or you won't be happy?
4 Data Declarations
Declaration format:
name: storage_type value(s)
Usually, an initial value is assigned to the variable; for .space, the size of space needed (in bytes) must be specified
Note: The name must always be followed by a colon
examplevar1: .word 3 # create a single integer variable with initial value 3
# Declare a word type variable var1, and assign it a value of 3
array1: .byte 'a','b'# create a 2-element character array with elements initialized# to a and b
# Declare an array array1 that stores 2 characters, and assign values 'a', 'b'
array2: .space 40 # allocate 40 consecutive bytes, with storage uninitialized
# could be used as a 40-element character array, or a# 10-element integer array; a comment should indicate which! # Allocate 40 bytes of uninitialized consecutive space for variable array2, of course, it is best to declare in advance what type of value this variable will store!
5 Loading and Saving [Reading and Writing]
1. If you want to access memory, sorry, you can only use load or store instructions
2. All other operations are strictly register operations
load: lw register_destination, RAM_source # copy word (4 bytes) at source RAM location to destination register.
# Copy the contents of RAM_source from memory to the corresponding register (the 'w' in lw means 'word', indicating that the data size is 4 bytes)
lb register_destination, RAM_source # copy byte at source RAM location to low-order byte of destination register, and sign-extend to higher-order bytes
# Same as above, lb means load byte
store word: sw register_source, RAM_destination # store word in source register into RAM destination
# Write the data from the specified register into the specified memory
sb register_source, RAM_destination # store byte (low-order) in source register into RAM destination
load immediate: li register_destination, value # load immediate value into destination register
Example
.data var1: .word 23 # declare storage for var1; initial value is 23
.text __start: lw $t0, var1 # load contents of RAM location into register $t0: $t0 = var1 li $t1, 5 # $t1 = 5 ("load immediate") sw $t1, var1 # store contents of register $t1 into RAM: var1 = $t1 done
6 Immediate and Indirect Addressing
load address: la $t0, var1 # Copy the RAM address of var1 into register $t0
indirect addressing: lw $t2, ($t0) # Load the value at the RAM address contained in $t0 into $t2
sw $t2, ($t0) # Store the value in register $t2 into the RAM at the address contained in $t0
based or indexed addressing: lw $t2, 4($t0) # Load the value at RAM address ($t0+4) into $t2
sw $t2, -12($t0) # Store the value in register $t2 into the RAM at address ($t0-12)
Needless to say, addressing that requires offsets is primarily used in two scenarios: arrays and stacks.
.data array1: .space 12 # declare 12 bytes of storage to hold array of 3 integers # Define an array array1 of 12 bytes, accommodating 3 integers
.text __start: la $t0, array1 # load base address of array into register $t0 # Let $t0 = the base address of the array li $t1, 5 # $t1 = 5 ("load immediate") sw $t1, ($t0) # first array element set to 5; indirect addressing # Assign value to the first element of the array array[0] = $1 = 5 li $t1, 13 # $t1 = 13 sw $t1, 4($t0) # second array element set to 13 # Assign value to the second element of the array array[1] = $1 = 13 # (The address of each element in the array is spaced by the length of its data type, which is 4 bytes, so for array+4 it is array[1]) li $t1, -7 # $t1 = -7 sw $t1, 8($t0) # third array element set to -7 # Same as above, array+8 = (address[array[0])+4)+ 4 = address(array[1]) + 4 = address(array[2])
7 Arithmetic Instruction Set
1. Up to 3 operands
2. Here, operands can only be registers; addresses are absolutely not allowed
3. All instructions are uniformly 32 bits = 4 * 8 bits = 4 bytes = 1 word
add $t0,$t1,$t2 # $t0 = $t1 + $t2; add as signed (2's complement) integers
sub $t2,$t3,$t4 # $t2 = $t3 - $t4
addi $t2,$t3, 5 # $t2 = $t3 + 5; "add immediate" (no sub immediate)
addu $t1,$t6,$t7 # $t1 = $t6 + $t7; add as unsigned integers
subu $t1,$t6,$t7 # $t1 = $t6 - $t7; subtract as unsigned integers
mult $t3,$t4 # multiply 32-bit quantities in $t3 and $t4, and store 64-bit
# result in special registers Lo and Hi: (Hi,Lo) = $t3 * $t4
div $t5,$t6 # Lo = $t5 / $t6 (integer quotient)
# Hi = $t5 mod $t6 (remainder)
mfhi $t0 # move quantity in special register Hi to $t0: $t0 = Hi
mflo $t1 # move quantity in special register Lo to $t1: $t1 = Lo
# used to get at result of product or quotient
move $t2,$t3 # $t2 = $t3
8 Control Flow
Branches (if-else series)
The instructions include conditional comparisons for branching:
b target # unconditional branch to program label target
beq $t0,$t1,target # branch to target if $t0 = $t1
blt $t0,$t1,target # branch to target if $t0 < $t1
ble $t0,$t1,target # branch to target if $t0 <= $t1
bgt $t0,$t1,target # branch to target if $t0 > $t1
bge $t0,$t1,target # branch to target if $t0 >= $t1
bne $t0,$t1,target # branch to target if $t0 != $t1
Jumps (while, for, goto series)
j target # unconditional jump to program label target # Jump unconditionally, without considering any conditions
jr $t3 # jump to address contained in $t3 ("jump register") # Similar to relative addressing, jump to the address given by this register
Subroutine calls return: “jump register” instruction
jr $ra # "jump register"
Jump to the return address stored in register $ra (stored by the jal instruction)
If the called subroutine calls other subroutines, the return addresses are stored on the stack, as $ra can only hold one address (I can’t clone myself)
9 System Calls and Input/Output
1. System calls are used to implement terminal input and output, as well as to declare program termination
2. Learn to use syscall
3. Registers used for parameters: $v0, $a0, $a1
4. Return value uses: $v0
The general idea is that the string to be printed should have a terminator, similar to ‘