# Comments starts with the symbol '#' and continues to the end of the line.
# ---------------------------------------------------------------------------
# PURPOSE: Small tutorial demonstrating the basics of MIPS assembly.
# The tutorial introduces the following MIPS instructions.
#   Instruction   Meaning
#   ----------------------------------------
#   li            Load Immediate
#   la            Load Address
#   lw            Load Word
#   add           Add
#   addi          Add Immediate
#   sw            Store Word
#   move          Move (copy) register
#
# The tutorial introduces the following SPIM/MARS built in system calls.
#   System call   Code
#   ------------------------
#   print_string  4
#   print_int     1
#   print_char   11
#   exit         10
#
# The tutorial introduces the following MIPS assembler directives.
#   Directive   Description
#   ----------------------------------------------------------------------
#   .data       Subsequent items are stored in the data segment.
#   .text       Subsequent items are put in the user text seg- ment.
#   .space      Allocate n bytes of space in the current segment.
#   .word n     Store the integer n as 4 byte word in the current segment.
#   .asciiz     Store the string str in memory and null-termi- nate it.
#
# AUTHOR:      Karl Marklund <karl.marklund@it.uu.se>, 2015-12-10
# Modified by: Henke Alfken(Schulze), 2018-03-31
# ---------------------------------------------------------------------------

# ---------------------------------------------------------------------------
# DATA SEGMENT: Data used by the program is declared in the data segment.
# ---------------------------------------------------------------------------
  .data

# Store value 9 as a 4 byte (a word) size signed integer at label x.
x:  .word 9

# Reserve four bytes (a word) at label y.
y:   .space 4

# Reserve four bytes (a word) at label z.
z:   .space 4

# Store a null terminated string at label msg.
msg:  .asciiz "Hello world!\n"

# Store new line as a null terminated string at label newline.
newline:   .asciiz "\n"

# ---------------------------------------------------------------------------
# MAIN: Text segment (code) for the program.
# ---------------------------------------------------------------------------
  .text

# Execution starts at the label main.
main:
  ##### li - Load Immediate 
  # To store a value in a register, the li instruction can be used:
  li $t0, 5         # Load the immediate value 5 into register $t0 = R08.
  # Note that li is a pseudo instruction that gets translated to a addiu
  # (Add Immediate Unsigned) instruction by the assemblator.

  ##### la - Load Address
  # Use the la instruction to store the address of a label in a register.
  la $t1, x         # Load the _address_ of label x into register $t1 = R09.
  # NOTE: la is a pseudo instruction that the assemblator translates to two instructions:
  # One lui (Load Upper Immediate) instruction setting $ta (address translate).
  # One ori (OR Immediate) storing the memory address of the label in register $t1.

  ##### lw - Load Word
  # To load a four byte (word) value from memory, use the lw instruction.
  # The bare machine provides only one memory-addressing mode:
  #    c(rx)
  # , which uses the sum of the immediate c and register rx as the address.
  lw $t2, 0($t1)    # Load the value 9 at address 0 + $t1 into register $t2 = R10.

  # An alternative addressing mode uses only a label.
  lw $t3, x         # Load the _value_ 9 stored at label x into regiser $t3 = R11.

  # NOTE: when using the above adressing mode (label) the assemblator
  # translates the single lw instruction to two instructions:
  # One lui (Load Upper Immediate) instruction storing the memory address of
  # the label in register $at (address translation register).
  # One lw instruction with  address mode c(rx), which uses the sum of the
  # immediate c and register rx as the address.

  ##### add - Addition #####
  # Use the add instruction to store the result of adding two registers.
  add $t4, $t0, $t2 # Add $t0=5 and $t2=9, store the result=0xe into register $t4 = R12.

  # Note that 5 + 9 = 14 = 0x0000000e.
  # Use the addi instruction to add an immediate value to the content of a register.
  ##### addi - Add Immediate
  addi $t5, $t4, 1  # Add 1 to $t4 and store the result=0xf into register $t5 = R13.
  # Note that 14 + 1 = 15 = 0x0000000f

  ##### sw - Store Word
  # Use the sw instruction to write the value in a register to memory.
  # The bare machine provides only one memory-addressing mode:
  #    c(rx)
  # , which uses the sum of the immediate c and register rx as the address.
  sw $t5, 0($t1)    # Store the value in register $t5 at address 0 + $t1.
  sw $t5, z         # Store the value in $t5 to the address of label <z>.

  # NOTE: when using the above adressing mode (label) the assemblator
  # translates the single lw instruction to two instructions:
  # * One lui (Load Upper Immediate) instruction storing the memory address of
  #   the label in register $at (address translation register).
  # * One lw instruction with  address mode c(rx), which uses the sum of the
  #   immediate c and register rx as the address.

  ##### move
  # To copy the value in one register into another register, use the move instruction.
  move $t6, $t5     # Copy the value in $t5 into $t6 = R14.

  ##### print_string (system call)
  li $v0, 4         # Set the system call code 4 (print_string) to register $v0 = R02.
  la $a0, msg       # Load the address of <msg> into register $a0 = R04.
  syscall           # The syscall instruction prints what $a0 = R04 points to.
  
  ##### print_int (system call)
  li $v0, 1         # Set the system call code 1 (print_int) to register $v0.
  li $a0, 127       # Load the value 127=0x7f into register $a0.
  syscall           # The syscall instruction prints the integer.
  # NOTE: system call code already set to 1 (print_int) in $a0.

  # Print new line:
  li $v0, 4         # System call code 4 (print_string).
  la $a0, newline   # Load the address of <newline> into register $a0.
  syscall           # Print the new line.

  # Can use move to print the value of any register:
  li $v0, 1         # System call code 1 (print_int).
  move $a0, $t6     # Copy the value in $t6 to $a0.
  syscall           # Print the value in $t6, 0xf = 15.

  ##### print_char (system call)
  li $v0, 11        # System call code 11 (print_char).
  li $a0, 0x40      # Load the ASCII value of '@' into $a0.
  syscall           # Print '@' (ASCII 0x40).

  ##### exit (system call)
    li $v0, 10      # Use the system call code 10 to exit.
    syscall         # System call code 10 to terminate normally.
