################################################################################
##
## LSU EE 4720 Spring 2022 Homework 1
##
##
 ## Due Midnight  4 February 2022

 # Assignment https://www.ece.lsu.edu/ee4720/2022/hw01.pdf

 ## Instructions:
  #
  # (0) Read and follow account setup instructions at
  #     https://www.ece.lsu.edu/ee4720/proc.html
  #
  # (1) Use this file for your
  #     solution.  The TA-bot will look first for a file named ~/hw01/hw01.s.
  #     If you have multiple versions make sure the one you want graded
  #     is in ~/hw01/hw01.s.
  #
  # (2) Find the problems in this file and solve them.
  #
  #     A procedure shell has been provided for 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
  #     directory and filename given above.  (Line labels may be added.)
  #
  # (3) Your solution will automatically be copied from your account by
  #     the TA-bot.  Late submissions can be E-mailed.
  #

 ## Additional Resources
  #
  # MIPS Architecture Manual Volume 2 (Contains a list of instructions.)
  #      https://www.ece.lsu.edu/ee4720/mips32v2.pdf
  #      Note: SPIM implements MIPS-I instructions.
  #
  # SPIM Documentation:
  #      https://www.ece.lsu.edu/3755/spim.pdf
  #
  # Account Setup and Emacs (Text Editor) Instructions
  #      https://www.ece.lsu.edu/ee4720/proc.html
  #      To learn Emacs look for and follow instructions for the Emacs tutorial.
  #
  # Unix Help (Outdated, need a better link.)
  #      https://www.ece.lsu.edu/v/4ltrwrd/


################################################################################
## Problem 1
#
#  Instructions: https://www.ece.lsu.edu/ee4720/2022/hw01.pdf
#
#  Complete strlen_p1 so that the main loop uses a lw instruction.

strlen_p1:
        ## Register Usage
        #
        # CALL VALUE
        #  $a0: Address of first character of string.
        #       This address will be a multiple of 4.
        #
        # RETURN
        #  $v0: The length of the string (not including the null).
        #
        # Note:
        #  Can modify registers $t0-$t9, $a0-$a3, $v0, $v1.
        #  DO NOT modify other registers.
        #
        # [ ] The testbench should show 0 errors.
        # [ ] Try to reduce the number of executed instructions.
        # [ ] Do not use pseudoinstructions except for nop.
        #     Do not use: li, la, mov, bgt, blt, etc.
        #
        # [ ] Code should be efficient.
        # [ ] The code should be clearly written.
        # [ ] Comments should be written for an experienced programmer.

        addi $v0, $a0, 0
        
LOOP_P1:
        lhu $t0, 0($a0)
        andi $t1, $t0, 0xff00
        beq $t1, $0, DONE0
        andi $t1, $t0, 0xff
        bne $t1, $0, LOOP_P1
        addi $a0, $a0, 2

        sub $v0, $a0, $v0
        jr $ra
        addi $v0, $v0, -1

DONE0:
        jr $ra
        sub $v0, $a0, $v0


################################################################################
## Problem 2
#
#  Complete strlen_p2 so that it makes good use of the orc.b instruction.

strlen_p2:
        # CALL VALUE
        #  $a0: Address of first character of string.
        #       This address will be a multiple of 4.
        #
        # RETURN
        #  $v0: The length of the string (not including the null).
        #
        # Note:
        #  Can modify registers $t0-$t9, $a0-$a3, $v0, $v1.
        #  DO NOT modify other registers.
        #
        # [ ] Use lw to load from string. (Replace the lbu)
        # [ ] Make use of orc.b insn. Consider using clz, clo.
        # [ ] The testbench should show 0 errors.
        # [ ] Try to reduce the number of executed instructions.
        # [ ] Do not use pseudoinstructions except for nop.
        #     Do not use: li, la, mov, bgt, blt, etc.
        #
        # [ ] Code should be efficient.
        # [ ] The code should be clearly written.
        # [ ] Comments should be written for an experienced programmer.

        addi $v0, $a0, 1

LOOP_P2:
        lbu $t0, 0($a0)
        orc.b $t1, $t0         # Modify code so that $t1 is used!
        bne $t0, $0, LOOP_P2
        addi $a0, $a0, 1

        jr $ra
        sub $v0, $a0, $v0




##############################################################################
 #

strlen_ref:
        ## Register Usage
        #
        # $a0: Address of first character of string.
        # $v0: Return value, the length of the string.

        addi $v0, $a0, 1        # Set aside a copy of the string start + 1.
        
REF_LOOP:
        lbu $t0, 0($a0)         # Load next character in string into $t0
        bne $t0, $0, REF_LOOP   # If it's not zero, continue
        addi $a0, $a0, 1        # Increment address. (Note: Delay slot insn.)
                
        jr $ra
        sub $v0, $a0, $v0


##############################################################################
#
 ## Test Code
#
#  The code below calls the strlen routines.

        .data
str:
        .align 2
        .asciiz "1"
        .align 2, -1
        .asciiz "12"
        .align 2, -1
        .asciiz "123"
        .align 2, -1
        .asciiz "1234"
        .align 2, -1
        .asciiz "12345"
        .align 2, -1
        .asciiz ""
        .align 2, -1
        .asciiz "\"Per aspera, ad astra!\""
        .align 2, -1
        .ascii "eighteen quintillion, four hundred forty six quadrillion, "
        .ascii "seven hundred forty four trillion, seventy three billion, "
        .ascii "seven hundred nine million, five hundred fifty one thousand, "
        .asciiz "six hundred sixteen"
msg:
        .asciiz "String %/s2/2d: Length %/v1/3d is "
msg_good:
        .asciiz "correct. Took %/s4/3d insn or %/f6/.3f char/insn\n"
msg_bad:
        .asciiz "wrong. Should be %/s7/3d.\n"

mut_strlen_p1:
        .word strlen_p1
        .asciiz "strlen_p1  (Problem 1 - Bit Ops)"
mut_strlen_p2:
        .word strlen_p2
        .asciiz "strlen_p2  (Problem 2 - RISC V orc insn)"
mut_strlen_ref:
        .word strlen_ref
        .asciiz "strlen_ref (Simple strlen routine.)"
muts:
        .word mut_strlen_p1
        .word mut_strlen_p2
        .word mut_strlen_ref
        .word 0

mut_msg:
        .asciiz "\n** Starting Test of Routine \"%/t0/s\" **\n"

        .text
        .globl __start
__start:
        mtc0 $0, $22            # Pause tracing.
        addi $s1, $0, 0
TBOUTER:
        la $t0, muts
        sll $t1, $s1, 2
        add $t1, $t1, $t0
        lw $s0, 0($t1)

        bne $s0, $0, TB_MORE
        nop

        addi $v0, $0, 10        # System call code for exit.
        syscall
TB_MORE:

        la $a0, mut_msg
        addi $t0, $s0, 4
        addi $v0, $0, 11
        syscall

        la $a0, str
        addi $s6, $a0, 0        # Save copy of string starting address.
        addi $s2, $0, 0
TBLOOP:
        addi $a0, $s6, 0
        jal strlen_ref
        addi $s2, $s2, 1
        addi $s7, $v0, 0

        addi $a0, $s6, 0
        addi $v0, $0, -1
        lw $t0, 0($s0)
        mtc0 $v0, $22           # Resume tracing. (No effect if not stepping.)
        jalr $t0
        mfc0 $s5, $9            # Copy current instruction count. (Before.)
        mfc0 $s4, $9            # Copy current instruction count. (After.)
        mtc0 $0, $22            # Pause tracing.
        addi $s4, $s4, -1
        sub $s4, $s4, $s5
        mtc1 $s4, $f4
        cvt.d.w $f4, $f4
        mtc1 $v0, $f0
        cvt.d.w $f0, $f0
        div.d $f6, $f0, $f4
        
        addi $v1, $v0, 0        # Move length of string to $v1
        addi $v0, $0, 11        # System call code for message.
        la $a0, msg             # Address of message.
        syscall

        la $a0, msg_good
        beq $v1, $s7  TB_CONTINUE
        nop
        la $a0, msg_bad
TB_CONTINUE:
        syscall

        add $s6, $s6, $s7
        ori $s6, $s6, 0x3
        addi $s6, $s6, 1
        la $a0, msg
        slt $t0, $s6, $a0
        bne $t0, $0, TBLOOP
        nop

        j TBOUTER
        addi $s1, $s1, 1