A Ten-Minute Introduction to MIPS Programming

A Ten-Minute Introduction to MIPS Programming

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

A Ten-Minute Introduction to MIPS Programming

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

A Ten-Minute Introduction to MIPS Programming

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

A Ten-Minute Introduction to MIPS Programming

The general idea is that the string to be printed should have a terminator, similar to ‘’ in C; here we just need to declare the string as .asciiz type.Below is a prompt I used with Mars 4.4:

A Ten-Minute Introduction to MIPS Programming

1. For reading integers, floating-point numbers, and double precision data operations, the system will read an entire line (i.e., using the newline character as a marker ‘
‘)

2. read_string is similar to fgets

Example: Print an integer stored in register $2:

Print out integer value contained in register $t2
li  $v0, 1         # load appropriate system call code into register $v0;                   # Declare the operation code to be called as 1 (print_int) and assign it to $v0                   # code for printing integer is 1
move    $a0, $t2   # move integer to be printed into $a0:  $a0 = $t2                   # Assign the integer to be printed to $a0
syscall            # call operating system to perform operation

Example: Read a number and store it in the int_value variable in memory:

Read integer value, store in RAM location with label int_value (presumably declared in data section)
li  $v0, 5           # load appropriate system call code into register $v0;                     # code for reading integer is 5
syscall              # call operating system to perform operations
w  $v0, int_value   # value read from keyboard returned in register $v0;                     # store this in desired location

Example: Print a string (this is complete; actually, the above examples can directly replace the main: part and run directly)

    .datastring1    .asciiz  "Print this.\n"# declaration for string variable, # .asciiz directive makes string null terminated
    .text        main:    li  $v0, 4  # load appropriate system call code into register $v0;# code for printing string is 4                 la  $a0, string1# load address of string to be printed into $a0                  syscall  # call operating system to perform print operation

Example: When execution reaches here, the program ends immediately, regardless of what happens next~~

li  $v0, 10      # system call code for exit = 10
syscall           # call operating sys

References:

This article is a reprint, not original, with slight modifications: https://www.cnblogs.com/thoupin/p/4018455.html
The English version of this article can be found here: https://minnie.tuhs.org/CompArch/Resources/mips_quick_tutorial.html

Leave a Comment