MIPS Assembly

Личный сайт Go-разработчика из Казани

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.

Read More

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"