The MIPS (Microprocessor without Interlocked Pipeline Stages) Assembly language is designed to work with the MIPS microprocessor paradigm designed by J. L. Hennessy in 1981. These RISC processors are used in embedded systems such as gateways and routers.
1# Comments are denoted with a '#'
2
3# Everything that occurs after a '#' will be ignored by the assembler's lexer.
4
5# Programs typically contain a .data and .text sections
6
7.data # Section where data is stored in memory (allocated in RAM), similar to
8 # variables in higher-level languages
9
10 # Declarations follow a ( label: .type value(s) ) form of declaration
11 hello_world: .asciiz "Hello World\n" # Declare a null terminated string
12 num1: .word 42 # Integers are referred to as words
13 # (32-bit value)
14
15 arr1: .word 1, 2, 3, 4, 5 # Array of words
16 arr2: .byte 'a', 'b' # Array of chars (1 byte each)
17 buffer: .space 60 # Allocates space in the RAM
18 # (not cleared to 0)
19
20 # Datatype sizes
21 _byte: .byte 'a' # 1 byte
22 _halfword: .half 53 # 2 bytes
23 _word: .word 3 # 4 bytes
24 _float: .float 3.14 # 4 bytes
25 _double: .double 7.0 # 8 bytes
26
27 .align 2 # Memory alignment of data, where
28 # number indicates byte alignment
29 # in powers of 2. (.align 2
30 # represents word alignment since
31 # 2^2 = 4 bytes)
32
33.text # Section that contains
34 # instructions and program logic
35.globl _main # Declares an instruction label as
36 # global, making it accessible to
37 # other files
38
39 _main: # MIPS programs execute
40 # instructions sequentially, where
41 # the code under this label will be
42 # executed first
43
44 # Let's print "hello world"
45 la $a0, hello_world # Load address of string stored
46 # in memory
47 li $v0, 4 # Load the syscall value (number
48 # indicating which syscall to make)
49 syscall # Perform the specified syscall
50 # with the given argument ($a0)
51
52 # Registers (used to hold data during program execution)
53 # $t0 - $t9 # Temporary registers used for
54 # intermediate calculations inside
55 # subroutines (not saved across
56 # function calls)
57
58 # $s0 - $s7 # Saved registers where values are
59 # saved across subroutine calls.
60 # Typically saved in stack
61
62 # $a0 - $a3 # Argument registers for passing in
63 # arguments for subroutines
64 # $v0 - $v1 # Return registers for returning
65 # values to caller function
66
67 # Types of load/store instructions
68 la $t0, label # Copy the address of a value in
69 # memory specified by the label
70 # into register $t0
71 lw $t0, label # Copy a word value from memory
72 lw $t1, 4($s0) # Copy a word value from an address
73 # stored in a register with an
74 # offset of 4 bytes (addr + 4)
75 lb $t2, label # Copy a byte value to the
76 # lower order portion of
77 # the register $t2
78 lb $t2, 0($s0) # Copy a byte value from the source
79 # address in $s0 with offset 0
80 # Same idea with 'lh' for halfwords
81
82 sw $t0, label # Store word value into
83 # memory address mapped by label
84 sw $t0, 8($s0) # Store word value into address
85 # specified in $s0 and offset of
86 # 8 bytes
87 # Same idea using 'sb' and 'sh' for bytes and halfwords. 'sa' does not exist
88
89### Math ###
90 _math:
91 # Remember to load your values into a register
92 lw $t0, num # From the data section
93 li $t0, 5 # Or from an immediate (constant)
94 li $t1, 6
95 add $t2, $t0, $t1 # $t2 = $t0 + $t1
96 sub $t2, $t0, $t1 # $t2 = $t0 - $t1
97 mul $t2, $t0, $t1 # $t2 = $t0 * $t1
98 div $t2, $t0, $t1 # $t2 = $t0 / $t1 (Might not be
99 # supported in some versions of MARS)
100 div $t0, $t1 # Performs $t0 / $t1. Get the
101 # quotient using 'mflo' and
102 # remainder using 'mfhi'
103
104 # Bitwise Shifting
105 sll $t0, $t0, 2 # Bitwise shift to the left with
106 # immediate (constant value) of 2
107 sllv $t0, $t1, $t2 # Shift left by a variable amount
108 # in register
109 srl $t0, $t0, 5 # Bitwise shift to the right (does
110 # not sign preserve, sign-extends
111 # with 0)
112 srlv $t0, $t1, $t2 # Shift right by a variable amount
113 # in a register
114 sra $t0, $t0, 7 # Bitwise arithmetic shift to
115 # the right (preserves sign)
116 srav $t0, $t1, $t2 # Shift right by a variable amount
117 # in a register
118
119 # Bitwise operators
120 and $t0, $t1, $t2 # Bitwise AND
121 andi $t0, $t1, 0xFFF # Bitwise AND with immediate
122 or $t0, $t1, $t2 # Bitwise OR
123 ori $t0, $t1, 0xFFF # Bitwise OR with immediate
124 xor $t0, $t1, $t2 # Bitwise XOR
125 xori $t0, $t1, 0xFFF # Bitwise XOR with immediate
126 nor $t0, $t1, $t2 # Bitwise NOR
127
128## BRANCHING ##
129 _branching:
130 # The basic format of these branching instructions typically follow <instr>
131 # <reg1> <reg2> <label> where label is the label we want to jump to if the
132 # given conditional evaluates to true
133 # Sometimes it is easier to write the conditional logic backward, as seen
134 # in the simple if statement example below
135
136 beq $t0, $t1, reg_eq # Will branch to reg_eq if
137 # $t0 == $t1, otherwise
138 # execute the next line
139 bne $t0, $t1, reg_neq # Branches when $t0 != $t1
140 b branch_target # Unconditional branch, will
141 # always execute
142 beqz $t0, req_eq_zero # Branches when $t0 == 0
143 bnez $t0, req_neq_zero # Branches when $t0 != 0
144 bgt $t0, $t1, t0_gt_t1 # Branches when $t0 > $t1
145 bge $t0, $t1, t0_gte_t1 # Branches when $t0 >= $t1
146 bgtz $t0, t0_gt0 # Branches when $t0 > 0
147 blt $t0, $t1, t0_gt_t1 # Branches when $t0 < $t1
148 ble $t0, $t1, t0_gte_t1 # Branches when $t0 <= $t1
149 bltz $t0, t0_lt0 # Branches when $t0 < 0
150 slt $s0, $t0, $t1 # "Set on Less Than"
151 # when $t0 < $t1 with result in $s0
152 # (1 for true)
153
154 # Simple if statement
155 # if (i == j)
156 # f = g + h;
157 # f = f - i;
158
159 # Let $s0 = f, $s1 = g, $s2 = h, $s3 = i, $s4 = j
160 bne $s3, $s4, L1 # if (i !=j)
161 add $s0, $s1, $s2 # f = g + h
162
163 L1:
164 sub $s0, $s0, $s3 # f = f - i
165
166 # Below is an example of finding the max of 3 numbers
167 # A direct translation in Java from MIPS logic:
168 # if (a > b)
169 # if (a > c)
170 # max = a;
171 # else
172 # max = c;
173 # else
174 # if (b > c)
175 # max = b;
176 # else
177 # max = c;
178
179 # Let $s0 = a, $s1 = b, $s2 = c, $v0 = return register
180 ble $s0, $s1, a_LTE_b # if(a <= b) branch(a_LTE_b)
181 ble $s0, $s2, max_C # if(a > b && a <=c) branch(max_C)
182 move $v0, $s0 # else [a > b && a > c] max = a
183 j done # Jump to the end of the program
184
185 a_LTE_b: # Label for when a <= b
186 ble $s1, $s2, max_C # if(a <= b && b <= c) branch(max_C)
187 move $v0, $s1 # if(a <= b && b > c) max = b
188 j done # Jump to done
189
190 max_C:
191 move $v0, $s2 # max = c
192
193 done: # End of program
194
195## LOOPS ##
196 _loops:
197 # The basic structure of loops is having an exit condition and a jump
198 # instruction to continue its execution
199 li $t0, 0
200 while:
201 bgt $t0, 9, end_while # While $t0 is less than 10,
202 # keep iterating
203 #actual loop content would go here
204 addi $t0, $t0, 1 # Increment the value
205 j while # Jump back to the beginning of
206 # the loop
207 end_while:
208
209 # 2D Matrix Traversal
210 # Assume that $a0 stores the address of an integer matrix which is 3 x 3
211 li $t0, 0 # Counter for i
212 li $t1, 0 # Counter for j
213 matrix_row:
214 bgt $t0, 3, matrix_row_end
215
216 matrix_col:
217 bgt $t1, 3, matrix_col_end
218
219 # Do stuff
220
221 addi $t1, $t1, 1 # Increment the col counter
222 matrix_col_end:
223
224 # Do stuff
225
226 addi $t0, $t0, 1
227 matrix_row_end:
228
229## FUNCTIONS ##
230 _functions:
231 # Functions are callable procedures that can accept arguments and return
232 # values all denoted with labels, like above
233
234 main: # Programs begin with main func
235 jal return_1 # jal will store the current PC in $ra
236 # and then jump to return_1
237
238 # What if we want to pass in args?
239 # First we must pass in our parameters to the argument registers
240 li $a0, 1
241 li $a1, 2
242 jal sum # Now we can call the function
243
244 # How about recursion?
245 # This is a bit more work since we need to make sure we save and restore
246 # the previous PC in $ra since jal will automatically overwrite
247 # on each call
248 li $a0, 3
249 jal fact
250
251 li $v0, 10
252 syscall
253
254 # This function returns 1
255 return_1:
256 li $v0, 1 # Load val in return register $v0
257 jr $ra # Jump back to old PC to continue exec
258
259
260 # Function with 2 args
261 sum:
262 add $v0, $a0, $a1
263 jr $ra # Return
264
265 # Recursive function to find factorial
266 fact:
267 addi $sp, $sp, -8 # Allocate space in stack
268 sw $s0, ($sp) # Store reg that holds current num
269 sw $ra, 4($sp) # Store previous PC
270
271 li $v0, 1 # Init return value
272 beq $a0, 0, fact_done # Finish if param is 0
273
274 # Otherwise, continue recursion
275 move $s0, $a0 # Copy $a0 to $s0
276 sub $a0, $a0, 1
277 jal fact
278
279 mul $v0, $s0, $v0 # Multiplication is done
280
281 fact_done:
282 lw $s0, ($sp)
283 lw $ra, 4($sp) # Restore the PC
284 addi $sp, $sp, 8
285
286 jr $ra
287
288## MACROS ##
289 _macros:
290 # Macros are extremely useful for substituting repeated code blocks with a
291 # single label for better readability
292 # These are in no means substitutes for functions
293 # These must be declared before it is used
294
295 # Macro for printing newlines (since these can be very repetitive)
296 .macro println()
297 la $a0, newline # New line string stored here
298 li $v0, 4
299 syscall
300 .end_macro
301
302 println() # Assembler will copy that block of
303 # code here before running
304
305 # Parameters can be passed in through macros.
306 # These are denoted by a '%' sign with any name you choose
307 .macro print_int(%num)
308 li $v0, 1
309 lw $a0, %num
310 syscall
311 .end_macro
312
313 li $t0, 1
314 print_int($t0)
315
316 # We can also pass in immediates for macros
317 .macro immediates(%a, %b)
318 add $t0, %a, %b
319 .end_macro
320
321 immediates(3, 5)
322
323 # Along with passing in labels
324 .macro print(%string)
325 la $a0, %string
326 li $v0, 4
327 syscall
328 .end_macro
329
330 print(hello_world)
331
332## ARRAYS ##
333.data
334 list: .word 3, 0, 1, 2, 6 # This is an array of words
335 char_arr: .asciiz "hello" # This is a char array
336 buffer: .space 128 # Allocates a block in memory, does
337 # not automatically clear
338 # These blocks of memory are aligned
339 # next to each other
340
341.text
342 la $s0, list # Load address of list
343 li $t0, 0 # Counter
344 li $t1, 5 # Length of the list
345
346 loop:
347 bge $t0, $t1, end_loop
348
349 lw $a0, ($s0)
350 li $v0, 1
351 syscall # Print the number
352
353 addi $s0, $s0, 4 # Size of a word is 4 bytes
354 addi $t0, $t0, 1 # Increment
355 j loop
356 end_loop:
357
358## INCLUDE ##
359# You do this to import external files into your program (behind the scenes,
360# it really just takes whatever code that is in that file and places it where
361# the include statement is)
362.include "somefile.asm"