################################################################################
##
## UofSC CSCE 212 Spring 2021 Homework 1
##
##

 ## Instructions:
  #
  # (0) Read and follow the instructions here
  #     https://pooyanjamshidi.github.io/csce212/proc/
  #
  #
  # (1) Find the problem in this file and solve it.
  #
  #     A procedure shell has been provided for the each problem.  Place
  #     your solution there.
  #
  #     Assembler code following the problem runs your solution.
  #     That code can be modified.
  #
  #     Your entire solution should be in this file.
  #
  #     Do not rename the line labels in this file and be sure to use the
  #     filename given above.  (Line labels may be added.)
  #
  # (2) Submit this file after you solve the problem.
  #

 ## Additional Resources
  #
  # MIPS Instruction Set Quick Reference
  #      https://pooyanjamshidi.github.io/csce212/assets/resources/MIPS-QRC.pdf
  #
  # SPIM Documentation:
  #      https://pooyanjamshidi.github.io/csce212/assets/resources/spim.pdf


################################################################################
## Problem 1
#
# Complete the following procedure so that it returns the value of a bit from a
# bit vector that spans one or more bytes. Register `$a0` holds the start
# address of the bit vector and register `$a1` holds the bit number to retrieve.
# The most-significant bit of the first byte is bit number 0 (remember that MIPS
# is big-endian). The return value (i.e., the value of the register $v0) should
# be set to 0 or 1.

# For example, a 16-bit bit vector is specified in the assembler below starting
# at the label bit_vector_start:

# bit_vector_start:
# .byte 0xc5, 0x1f

# In binary this would be 1100 0101 0001 1111. If getbit were called with $a1=0
# then bit number zero, meaning the leftmost bit in 1100 0101 0001 11112, should
# be returned and so $v0=1. For $a1=2 a 0 should be returned.

# When you run the code in hw1.s a testbench routine will call getbit several
# times. For each call the testbench will print the value returned by getbit
# (meaning the value of $v0), whether that value is correct, and if wrong, the
# correct value. At the end it will print the number of incorrect values
# returned by getbit, which hopefully will be zero when you are done.

# It is important that each line of code is commented succinctly with enough
# clarity so anyone can follow the logic behind your code. Again writing comment
# is part of the solution, code without sufficient comments even if it is
# correct, will only receive half of the grade.

.text

getbit:
        ## Register Usage
        #
        # CALL VALUES
        #  $a0: Address of start of bit vector.
        #  $a1: Bit number to retrieve.
        #
        # RETURN
        #  $v0: The bit. (Zero or one.)
        #
        # Note:
        #  Can modify registers $t0-$t9, $a0-$a3, $v0, $v1.
        #  DO NOT modify other registers.
        #
        # [ ] The testbench should show 0 errors.
        # [ ] Code should be reasonably efficient.
        # [ ] The code should be clearly written.
        # [ ] Comments should be written for an experienced programmer.

        # write your code here


        jr $ra
        nop    

################################################################################
## Problem 2
#
## The code below implement the testbench routine, where multiple test cases are defined and get executed to evaluate whether the code you implemented in getbit is correct or not. 
# Your task is to refactor the code in a way to preserve its semantic, i.e.,
# preserve its functionality, but having less number of instructions. Note that
# your are not allowed to use psuedoinstructions (except for `nop` and `la`) to
# reduce the lines of code. You need to first understand how the procedure is
# implemented, grasp the logic behind it and then try to come up with some code
# transformations to reduce the number of instructions. You need to explain your
# code transformation with enough details so we can understand what changes has
# been done, indicating to particular lines that has been changed. In addition
# to the explanation, you need to compare the total lines of code when you open
# this file before and after refactoring. Simply Answer your question as
# follows:
# 2.1 Explanation regarding the refactoring:
# 2.2 How many lines of code were reduced:
# 2.3 What did you do to check the refactoring you made did not change the
# semantic of the testbench procedure?
#
# For each test there is one line consisting of a bit number and the expected
# return value. For example, the second test sets $a1=4 and expects a return
# value of $v0=0.

        .data
        .align 4
bit_vector_start:  # Note: MIPS is big-endian.
        .byte 0xc5, 0x1f
        .half 0x05af
        .word 0xedcba987
        .ascii "1234"
bit_vector_end:
testdata:
        .half 0, 1
        .half 4, 1
        .half 10, 0
        .half 16, 1, 20, 1, 21, 1         # The part specified using ".half"
        .half 32, 1, 35, 0, 39, 1, 63, 1  # The part specified using ".word"
        .half 5, 1
        .half 6, 0
        .half 1, 1
        .half 2, 0
        .half 11, 1
        .half 12, 1
        .half 13, 1
        .half 3, 0
        .half 7, 1
        .half 8, 0
        .half 9, 0
        .half 14, 1
        .half 15, 1
        .half -1, -1

msg_correct:
        .asciiz "\nCorrect answer"
msg_incorrect:
        .asciiz "\nIncorrect, correct answer: "
msg_total_incorrect:
        .asciiz "\nNumber of Incorrect Answers: "
msg_total:
        .asciiz "\nTotal Number of Tests: "
msg_score:
        .asciiz "\nFinal Score (out of 100): "
        .text

        .globl main
main:
        la $s0, bit_vector_start
        la $s1, testdata
        addi $s6, $0, 0    # number of errors, i.e., incorrect answers from the test data
        addi $s7, $0, 0    # total test cases

TB_LOOP:
        addi $a0, $s0, 0
        lh $a1, 0($s1)     # retrieving the first halfword of the memory address, see the testdata, we use .half (16 bits), so this instruction put the first number in $a1 
        bltz $a1 TB_DONE   # note that the last test case we use is -1, so it branches to TB_DONE if $a1 contains this last item in the list
        addi $s7, $s7, 1   # increment the number of test cases
        nop
        jal getbit         # this calls your function here
        nop
        move $s4, $v0      # put the return value to $s4 
        lhu $s5, 2($s1)    # this will put the second number into $s5
        la $a0, msg_correct
        beq $s4, $s5, TB_CORRECT  # check whether the answer provided by getbit is equal to the correct answer specified in the testdata and branch to TB_CORRECT 

TB_INCORRECT:
        la $a0, msg_incorrect
        addi $v0, $0, 4
        syscall
        nop
        move $a0, $s5
        addi $v0, $0, 1
        syscall
        nop
        addi $s1, $s1, 4 # incrementing $s1 so it points to the next address in memory, note that MIPS memory is byte addressable so that is why we are adding 4 here.
        addi $s6, $s6, 1 # increment the number of incorrect answers
        j TB_LOOP

TB_CORRECT:
        addi $v0, $0, 4
        syscall
        nop
        addi $s1, $s1, 4 # incrementing $s1 so it points to the next address in memory, note that MIPS memory is byte addressable so that is why we are adding 4 here.
        j TB_LOOP
        
TB_DONE:
        la $a0, msg_total_incorrect
        addi $v0, $0, 4
        syscall
        nop
        move $a0, $s6
        addi $v0, $0, 1
        syscall
        nop
        la $a0, msg_total
        addi $v0, $0, 4
        syscall
        nop
        move $a0, $s7
        addi $v0, $0, 1
        syscall
        nop
        la $a0, msg_score
        addi $v0, $0, 4
        syscall
        nop

## Problem 2.4
#
# Explain what this part of the code performs.
# 
TB_XYZ:
        subu $t0, $s7, $s6 
        divu $t0, $s7
        mfhi $t1
        mflo $t2
        addi $t3, 100
        mult $t2, $t3			
        mflo $t4				
        addu $t5, $t4, $t1 
        move $a0, $t5
        addi $v0, $0, 1
        syscall
        nop

        addi $v0, $0, 10  # exit
        syscall
        nop