# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
# Uppsala University - 2018 Spring
# Computer Architecture, 1DT093
# Lab 1 - Arrayer, Strängar, Loopar och Subrutiner.
# Copyright 2018 Nånne Bink & Ninne Honk, Group Ö 97
# Inspired by:
#   http://www.eit.lth.se/fileadmin/eit/courses/eit090/MIPS_IR.pdf
#   http://www.mrc.uidaho.edu/mrc/people/jff/digital/MIPSir.html
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
  .data
ARRAY_SIZE:       .word 1  # Change here to try other values (less than 10)
FIBONACCI_ARRAY:  .word 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89
STR_str:          .asciiz "abc" # "abcd" # "Hunden, Katten, Glassen"
  .globl DBG
  .text
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
# DESCRIPTION: For an array of integers, returns the total sum of all elements in the array.
#       INPUT: $a0 - address to first integer in array.
#              $a1 - size of array, i.e., numbers of integers in the array.
#      OUTPUT: $v0 - the total sum of all integers in the array.
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
integer_array_sum:
DBG:  ##### DEBUG BREAKPOINT ######
  addi $v0, $zero, 0     # Start of 1. integer_array_sum: initialize Sum to zero.
  add $t0, $zero, $zero  # Initialize array index i to zero.
for_all_in_array:
  #### Append a MIPS-instruktion before each of these comments:
  # Done if i == N
  # 4*i
  # address = ARRAY + 4*i
  # n = A[i]
  # Sum = Sum + n
  # i++
  # next element
end_for_all:
  jr $ra             # End of 1. integer_array_sum: jump back to the Return Address in $ra = R31.

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
# DESCRIPTION: Gives the length of a string.
#       INPUT: $a0 - address to a NUL terminated string.
#      OUTPUT: $v0 - length of the string (NUL excluded).
#    EXAMPLES: string_length("abcd") == 4.
#              string_length("") == 0.
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
string_length:
  #### Write your solution here ####
  jr $ra             # End of 2. string_length: jump back to the Return Address in $ra = R31.

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
# DESCRIPTION: For each of the characters in a string (from left to right), call a callback
#              subroutine. The callback suboutine will be called with the address of the
#              character as the input parameter ($a0).
#       INPUT: $a0 - address to a NUL-terminated string.
#              $a1 - address to a callback subroutine.
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
string_for_each:
  addi $sp, $sp, -4  # Start of 3. string_for_each: prepare the stack pointer for a push.
  sw $ra, 0($sp)     # PUSH the caller's Return Address to the stack.

  #### Write your solution here ####

  lw $ra, 0($sp)     # POP the Return Address to go to the caller's next instruction.
  addi $sp, $sp, 4   # Adjust the stack pointer after the pop.

  jr $ra             # End of 3. string_for_each: jump back to the Return Address in $ra = R31.

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
# DESCRIPTION: Transforms a lower case character [a-z] to upper case [A-Z].
#       INPUT: $a0 - address of a character
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
to_upper:
  #### Write your solution here ####
  jr $ra             # End of 4. to_upper: jump back to the Return Address in $ra = R31.

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
      # = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = #
      # = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = #
      #         You don't have to change anyghing below this line, except for         #
      #         task 5. Which part of the "main" section should you modify?           #
      # = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = #
      # = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = #
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
# Strings used by main:
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
  .data
NewLine:                 .asciiz "\n"
STR_sum_of_fibonacci_a:  .asciiz "The sum of the "
STR_sum_of_fibonacci_b:  .asciiz " first Fibonacci numbers is "
STR_string_length:       .asciiz  "\nstring_length(str) = "
STR_for_each_ascii:      .asciiz "\nstring_for_each(str, ascii) starts on the next line:"
STR_for_each_to_upper:   .asciiz "\nstring_for_each(str, to_upper) on the next line:\n"
  .text
  .globl main
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
# MAIN: Main calls various subroutines and prints out results.
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
main:
  addi $sp, $sp, -4  # Start of main: prepare the stack pointer for a push.
  sw $ra, 0($sp)     # PUSH the return address to the stack (store word).

  ### integer_array_sum
  la $a0, STR_sum_of_fibonacci_a # Load the address of <fib-msgA> into register $a0 = R04.
  li $v0, 4          # Set the system call code to 4 (print_string) in register $v0 = R02.
  syscall            # Print the message that $a0 points to in memory.

  lw $a0, ARRAY_SIZE # Load the _value_ of <ARRAY_SIZE> into register $a0 = R04.
  li $v0, 1          # Set the system call code to 1 (print_int) in register $v0 = R02.
  syscall            # Print the number=ARRAY_SIZE that $a0 points to in memory.

  la $a0, STR_sum_of_fibonacci_b # Load the address of <fib-msgB> into register $a0 = R04.
  li $v0, 4          # Set the system call code to 4 in $v0 = R02 to print a string.
  syscall            # syscall prints the NUL terminated string that <$a0> points to.

  la $a0, FIBONACCI_ARRAY # Load the address of <FIBONACCI_ARRAY> into $a0 = R04.
  lw $a1, ARRAY_SIZE # Load the _value_ of <ARRAY_SIZE> into $a1 = R05.
  jal integer_array_sum # 1. Call the function <integer_array_sum> with <$a0,$a1> as arguments.

  # Print the sum:
  add $a0, $v0, $zero# <integer_array_sum> has now returned the sum in $v0 = R02. Copy $v0
  li $v0, 1          # to $a0, and set the system call code to 1 in $v0 to print an int.
  syscall            # Call syscall to print the sum.
  li $v0, 4          # Next print
  la $a0, NewLine    # an end-of-line
  syscall            # character.

  ### string_length
  la $a0, STR_str    # Load the address of <STR_str> into $a0 = R04.
  jal print_test_string # Call the function <print_test_string> with <$a0> as argument.

  la $a0, STR_string_length # Load the address of <STR_string_length> into $a0 = R04.
  li $v0, 4          # Set the system call code to 4 in $v0 = R02 to print a string.
  syscall            # Print the message that label STR_string_length points to.

  la $a0, STR_str    # Load the address of <STR_str> into $a0 once more.
  jal string_length  # 2. Call the function <string_length> with <$a0> as argument.

  move $a0, $v0      # <string_length> has now returned the result in $v0 = R02. Copy to $a0.
  li $v0, 1          # Set the system call code to 1 in $v0 = R02 to print an int.
  syscall            # Call syscall to print the contents of $a0.

  ### string_for_each(string, ascii)
  la $a0, STR_for_each_ascii # Load the address of <STR_for_each_ascii> into $a0 = R04.
  li $v0, 4          # Set the system call code to 4 in $v0 = R02 to print a string.
  syscall            # syscall prints the NUL terminated string that <$a0> points to.

  la $a0, STR_str    # Load the address of <STR_str> into $a0 a third time.
  la $a1, ascii      # Load the address of the function <ascii> into $a1 = R05.
  jal string_for_each # 3. Call the function <string_for_each> with <$a0,$a1> as arguments.

  ### string_for_each(string, to_upper)
  la $a0, STR_for_each_to_upper # Load the address of <STR_for_each_to_upper>.
  li $v0, 4          # Set the system call code to 4 in $v0 = R02 to print a string.
  syscall            # Print the NUL terminated string that <STR_for_each_to_upper> points to.

  la $a0, STR_str    # Load the address of <STR_str> into $a0 a fourth time.
  la $a1, to_upper   # Load the address of the function <to_upper> into $a1 = R05.
  jal string_for_each # 4. Call the function <string_for_each> with <$a0,$a1> as arguments.

  la $a0, STR_str    # Load the address of <STR_str> into $a0 a fifth time.
  jal print_test_string # Call the function <print_test_string> with <$a0> as argument.

  lw $ra, 0($sp)     # POP the return address from the stack to $ra = R31.
  addi $sp, $sp, 4   # Adjust the stack pointer after the pop.

  ##### exit (system call)
  li $v0, 10  # Use the system call code 10 to 'terminate normally'.
  syscall     # End of main: bye-bye!

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
# DESCRIPTION: Prints out 'str = ' followed by the input string surrounded by double quotes.
#       INPUT: $a0 - address to a NUL terminated string.
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
print_test_string:
  .data
STR_str_is:
  .asciiz "str = \""
STR_quote:
  .asciiz "\""

  .text
  add $t0, $a0, $zero # Start of print_test_string: save the string's address from $a0 into $t0.

  la $a0, STR_str_is # Load the address of <STR_str_is>.
  li $v0, 4          # Set the system call code to 4 in $v0 = R02 to print a string.
  syscall            # Print the NUL terminated string that $a0 points to.

  add $a0, $t0, $zero # Restore the string's address from $t0 = R08 back to $a0 = R04.
  syscall            # Print the NUL terminated string that $a0 points to.

  la $a0, STR_quote  # Load the address of <STR_quote>.
  li $v0, 4          # Set the system call code to 4 in $v0 = R02 to print a string.
  syscall            # Print the NUL terminated string that $a0 points to.

  jr $ra             # End of print_test_string: jump back to the Return Address in $ra = R31.

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
# DESCRIPTION: Prints out the Ascii value of a character.
#       INPUT: $a0 - address of a character
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
ascii:
  .data
STR_the_ascii_value_is:
  .asciiz "\n  Ascii('X') = "

  .text
  la $t0, STR_the_ascii_value_is # Load the address of <STR_the_ascii_value_is> into $t0.

  # Replace X with the input character:
  add $t1, $t0, 10   # Start of ascii: save the address of X in "\n  Ascii('X') = " into $t1.
  lb $t2, 0($a0)     # Load the Ascii value of the character at 0($a0) into $t2 = R10.
  sb $t2, 0($t1)     # Replace the X with the Ascii value now in $t2, gotten from 0($a0).

  # Print "The Ascii value of...":
  add $a0, $t0, $zero # Copy the address of <STR_the_ascii_value_is> to $a0 = R04.
  li $v0, 4          # Set the system call code to 4 in $v0 = R02 to print a string.
  syscall            # Print the NUL terminated string that $a0 points to.

  # Append the Ascii value:
  add $a0, $t2, $zero # Copy the address of <STR_the_ascii_value_is>  to $a0 = R04.
  li $v0, 1          # Set the system call code to 1 in $v0 = R02 to print an int.
  syscall            # Call syscall to print the int that $a0 points to.

  jr $ra             # End of ascii: jump back to the Return Address in $ra = R31.
