+----------------------------+ | CMPS 224 MIPS Quick Guide | +----------------------------+ Data sizes - byte (8 bits), halfword (2 bytes), word (4 bytes) - a character is 1 byte of storage, integer is 1 word Instructions - an instructions uses 32 bits and comes in 3 format types (R,I,J) - R-type (all registers), I-type (register, immediate), J-type (jump) - pseudoinstructions are assembler macros: blt, bgt, ble, neg, not, bge, li Literal constants follow C syntax: - 99 (decimal int); 0x34 (hex int); 012 (octal int); 1.2 (decimal float) - characters enclosed in single quotes. e.g. 'b' - strings enclosed in double quotes. e.g. "Hello there." Labels - an identifier followed by a colon at beginning of a line: my_label: - specifies an address for an instruction or for data Registers - 32 general-purpose registers (GPRs) preceded by $ in instruction - may use register number e.g. $0..$31 or equivalentent names e.g. $t1, $sp - special registers lo/hi store result of multiplication and division - lo, hi addressable only by mfhi ("move from hi") and mflo ("move from Lo") - there are 32 floating point GPRs $f0 - $f31 on MIPS coprocessor - $a0 holds # cmdline args and $a1 holds address to cmdline structure Stack grows from high to low memory - minimum frame size 32 bytes # denotes that a comment follows - rest of line is ignored by assembler ------------------------------------------------------------------------------- Register AltName Description ------------------------------------------------------------------------------- $pc $pc Program Counter - indirectly set by jumps and branches $0 $zero hard-wired to the value 0 $1 $at (assembler temporary) reserved by the assembler $2-$3 $v0 - $v1 (values) from expression evaluation and function results $4-$7 $a0 - $a3 (args) 1st 4 arg for procedure; not preserved across calls $8-$15 $t0 - $t7 (temporaries) Caller-saved if needed; callee can use w/o saving; not preserved across procedure calls 16-23 $s0 - $s7 (saved values) Callee-saved; Callee saves original and restores before exiting; preserved across procedure calls $24-$25 $t8 - $t9 (tempories) same usage as $t0 - $t7 $26-$27 $k0 - $k1 reserved for use by the interrupt/trap handler $28 $gp Global Pointer; points to base of global data segment $29 $sp Stack Pointer; points to top of stack; doubleword aligned $30 $s8/$fp Frame Pointer; preserved across procedure calls $31 $ra Return Address Register $f0-$f31 floating point GPRs (not used in this course) +-------------------+ | PROGRAM STRUCTURE | +-------------------+ - a program is a plain text file with extension .s or .asm - code must be in section identified with assembler directive .text - placement of .data segment and .text segment is up to programmer - entry point for code execution is given label main: - ending point of main code is with exit system call (see System Calls) - Bare-bones outline of MIPS assembly language program .text # instructions follow this line # ... main: # indicates entry point (1st instruction to execute # ... .data # data storage instructions follow this line # ... +-------------------+ | DATA DECLARATIONS | +-------------------+ - MIPS is typeless - type is determined by instruction - data must be in section identified by assembler directive .data or .rdata - .data is static initialized data - .rdata is static read-only data (constant) - during execution storage is in .data or .rdata segments of the executable - format for storage is label: storage_type value(s) - the label refers to the address for data - create storage for variable of specified type, name and value - value is initial value or (for storage type .space) size to be allocated .data # data segment follows var1: .word 3 # create a single integer variable with initial value 3 stuff: .half 0x15 # 16-bit word initialized with hex value ptr: .word var1 # ptr is an alias to value at memory address var1 #Arrays array1: .byte 'a','b' # create 2-element char array; initialize to 'a' and 'b' array2: .space 40 # allocate 40 consecutive uninitialized bytes; could # hold 40 chars or 10 ints; use comment to indicate use array3: .word 0:10 # allocate 10 consecutive words aligned on word boundary # loads 32-bit integer value 0 in each word +---------------------------+ | LOAD & STORE INSTRUCTIONS | +---------------------------+ MIPS is a register-based load-store architecture; memory access only allowed with load and store instructions; all other instructions use register operands load: la $t0, label # load address of label into register lw $t1, ($t0) # load word (4 bytes) at RAM address into $t1 lb $t1, ($t0) # load byte at address $t0 to low-order byte of $t1, # sign-extend store: sw $t1, ($t0) # store value in $t1 to address in $t0 sb $t1, ($t0) # store byte (low-order) in $t1 to address in $t0 # Example Code: .data var1: .word 23 # create storage for 4 bytes; initial value is 23 .text __start: lw $t0, var1 # load contents of RAM location into reg $t0: $t0 = 23 li $t1, -5 # $t1 = -5, the value is sign extended as two's complement sw $t1, var1 # store contents of register $t1 into RAM: var1 = -5 +-------------------------------+ | INDIRECT AND BASED ADDRESSING | +-------------------------------+ la $t0, a_label # load RAM address of a_label into register $t0 Indirect addressing: (behaves like a pointer dereference) lw $t2, ($t0) # load word at RAM address contained in $t0 into $t2 sw $t2, ($t0) # store word in reg $t2 into RAM at address contained in $t0 Based or indexed addressing: (behaves like an index into an array) lw $t2, 4($t0) # load word at RAM address ($t0+4) into register $t2 sw $t2, -12($t0) # store word in $t2 into RAM at address $t0 minus 12 Use base addressing for arrays (elements are an offset from base address) and stacks (elements are offset from stack pointer or frame pointer; Example: .data array1: .space 12 # declare 12 bytes of storage for array of 3 ints .text __start: la $t0, array1 # load base address of array into register $t0 li $t1, 5 # $t1 = 5 ("load immediate") sw $t1, ($t0) # first array element set to 5; indirect addressing li $t1, 13 # $t1 = 13 sw $t1, 4($t0) # second array element set to 13 li $t1, -7 # $t1 = -7 sw $t1, 8($t0) # third array element set to -7 +--------------------------+ | SHIFT & BIT INSTRUCTIONS | +--------------------------+ sll $t0, $t1, 5 # shift left value in $t1 by 5 bits, store result in $t0 srl $t0, $t1, 5 # shift right value in $t1 by 5 bits, store result in $t0 and $t0, $t1, $t2 # bitwise AND $t1 with $t2, store result in $t0 ori $t0, $t1, 15 # bitwise OR $t1 with 15, store result in $t0 +-------------------------+ | ARITHMETIC INSTRUCTIONS | +-------------------------+ - all operands are registers or immediates; no RAM or indirect addressing - operand size is one word (4 bytes); immediates are sign-extended to 32 bits - overflow means result exceeds maximum value and exception handler is called - no overflow means value is undetermined but exception handler is not called li $t1, value # load 16-bit value into $t1, sign-extend to 32 bits; 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" (with overflow) addiu $t2,$t3, -5 # $t2 = $t3 + -5; "add immediate" (no overflow) addu $t1,$t6,$t7 # $t1 = $t6 + $t7; add as unsigned integer (no overflow) subu $t1,$t6,$t7 # $t1 = $t6 - $t7; subtract as unsigned integers mult $t3,$t4 # store 64-bit result in HiLo: Lo(low order); Hi(high order) div $t5,$t6 # $t5/$t6; lo=quotient; hi = remainder divu $t5,$t6 # unsigned values in $t5 and $t6; store in Lo and Hi as div mfhi $t0 # move quantity in special register Hi to $t0: $t0 = Hi mflo $t1 # move quantity in special register Lo to $t1: $t1 = Lo move $t2,$t3 # assign $t2 the value of $t3 +------------------+ | JUMPS & BRANCHES | +------------------+ Conditional Branches 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 beqz $t0, target # branch to target if t0 == 0 bltz $t0, target # branch to target if t0 < 0 Conditional Set Instructions slt $t0, $t1, $t2 # set t0 to 1 if t1 < t2 else set t0 to 0 sltiu $t0, $t1, 15 # t0 = (t1 < 15) ? 1 : 0, immediate unsigned Unconditional Jumps and Branches b target # branch to program label target (18-bit address) j target # jump to program label target (28-bit address) jr $t3 # jump to address contained in $t3 ("jump register") Subroutine Call jal a_label # jump and link; copy $pc to $ra; copy a_label to $pc Subroutine Return jr $ra # jump to address in register $ra (move $ra to $pc) Note: return address is in register $ra; if subroutine calls itself or other subroutines you must copy return address from $ra onto stack to preserve it; since jal always places return address in $ra it will be overwritten +---------------+ | SYSTEM CALLS | +---------------+ - syscall hands off control to kernel - supported syscalls is dependent upon the particular MIPS assembler - used to read/print values or strings from I/O window and exit program - load int syscall code in $v0; load args (if any) in $a0-$a1 or $f12 - result value (if any) returned in register $v0 - print_string service expects null-terminated string; .asciiz will do this - read_int, read_float and read_double grab line up to and incl. newline char - read_string service has same semantices as C library routine fgets: + reads up to n-1 chars into buffer and terminates string with null char + if fewer than n-1 chars are in current line, it reads up to and including the newline and terminates the string with a null character - sbrk service returns address to block of dynamic memory of n bytes - exit service stops a program from running and returns control to OS ------------------------------------------------------------------------------- SYSCALL SERVICES ------------------------------------------------------------------------------- Service $v0 ARGUMENTS | RESULTS --------------------------------------------------+---------------------------- print_int 1 $a0 = integer to be printed | --------------------------------------------------+---------------------------- print_float 2 $f12 = float to be printed | --------------------------------------------------+---------------------------- print_double 3 $f12 = double to be printed | --------------------------------------------------+---------------------------- print_string 4 $a0 = address of string in RAM | --------------------------------------------------+---------------------------- read_int 5 | integer returned in $v0 --------------------------------------------------+---------------------------- read_float 6 | float returned in $v0 --------------------------------------------------+---------------------------- read_double 7 | double returned in $v0 --------------------------------------------------+---------------------------- read_string 8 $a0=string address, $a1=length | string is at address in $a0 --------------------------------------------------+---------------------------- sbrk 9 $a0 = amount of memory | address returned in $v0 --------------------------------------------------+---------------------------- exit 10 | --------------------------------------------------+---------------------------- print_char 11 $a0 = char | --------------------------------------------------+---------------------------- read_char 12 | char in $v0 --------------------------------------------------+---------------------------- open 13 $a0=filename, $a1=flags,$a2=mode | file descriptor in $a0 --------------------------------------------------+---------------------------- read 14 $a0=file handle, $a1=buff, $a2=len| num chars read in $v0 --------------------------------------------------+---------------------------- write 15 $a0 = file descriptor, $a1=buffer| num chars written in $a0 $a2 = length | --------------------------------------------------+---------------------------- close 16 $a0 = file descriptor | --------------------------------------------------+---------------------------- exit2 17 $a0 = result | --------------------------------------------------'---------------------------- Code samples: ---------------------------------------------------- # Print out integer value contained in register $t2: li $v0, 1 # load system call code 1 into register $v0 (print_int) move $a0, $t2 # move integer to be printed into $a0: $a0 = $t2 syscall # call operating system to perform operation -------------------------------------------------------------- # Read integer, store at address in data section by int_value: li $v0, 5 # load call code 5 into register $v0 (read_int) syscall # call operating system to perform operation sw $v0, int_value # store value read from $v0 to location in RAM --------------------- # Print out a string: .data string1: .asciiz "Print me.\n" .text main: li $v0, 4 # code 4 is print a string la $a0, string1 # load address of string syscall # call operating system --------------------------- # How to exit your program: li $v0, 10 # system call code for exit = 10 syscall # call operating sys to execute system call 10