################################################################################
##
## LSU EE 4720 Spring 2026 Homework 1
##
##
 # Assignment https://www.ece.lsu.edu/ee4720/2026/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 problem in this file and solve it.
  #
  #     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/2026/hw01.pdf
#

reverse_lists:

        ## Register Usage
        #
        #  CALL VALUES
        #   $a0:  Address of string to read.
        #   $a1:  Address of string to write.
        #   $a2:  Address of scratch storage.
        #
        #  RETURN VALUES
        #   No return registers.
        #   Instead write memory starting at $a1 with string at $a0
        #   with its lists reversed.
        #
        ## Helpful Information
        #
        # Useful ASCII Characters (In Decimal)
        #    0  Null. Marks the end of the string.
        #   40  '(', Opening parenthesis.
        #   41  ')', Closing parenthesis.
        #   44  ',', A comma.
        #
        # Complete ASCII table: https://en.cppreference.com/w/cpp/language/ascii
        #
        ## Solution Checklist
        #
        # [ ] Reverse lists as described in the handout.
        # [ ] There should be no x's in testbench output Err lines.
        # [ ] Don't assume a maximum element length.
        # [ ] Don't assume a maximum list length.
        #
        # [ ] The fewer instructions executed, the better.
        # [ ] Write code clearly, comment for an expert MIPS programmer.
        # [ ] Do not use pseudoinstructions except for nop.
        # [ ] Don't forget that MIPS branches have delay slots.
        # [ ] Remove unneeded code.

        # Helpful Starter Code
        #
        ori $t3, $0, 40    # Open paren.
        ori $t4, $0, 41    # Close paren.
        ori $t5, $0, 44    # Comma
        #
        # Feel free to delete the lines above.

        lb $t0, 0($a0)   # Read first character of input string.
        sb $t0, 0($a1)   # Write first character of output string.

        
all_done:
        jal $ra
        nop



##############################################################################
#
## Test (Testbench) Code
#

        .data
test_string:
        .asciiz "This string has no lists to reverse."

        .ascii  "Total ice between a (lite,glaze), (locally,higher,amounts)"
        .asciiz " possible."

        .asciiz "Corner cases: (), (one), (a,,see), (,b,) (,d,e,)."

        .asciiz "(1,two,three,four,five,six,seven,eight,nine,ten)"
test_string_end:
        .byte 0


correct_string_start:
        .asciiz "This string has no lists to reverse."
        .asciiz "Total ice between a (glaze,lite), (amounts,higher,locally) possible."
        .asciiz "Corner cases: (), (one), (see,,a), (,b,) (,e,d,)."
        .asciiz "(ten,nine,eight,seven,six,five,four,three,two,1)"

error_mask_string:
        .space 256

output_string:
        .space 256

        .align 4
scratch_storage:
        .space 1024

msg_in:
        .ascii "---- Input number %/s6/i, length %/f0/.0f characters.\n"
        .asciiz "In : %/s7/s\n"
msg_out:
        .ascii "Out: %/s1/s\n"
#        .ascii "        .asciiz \"%/s1/s\"\n" # Used to print correct str.
        .ascii "Err: %/t0/s\n"
        .asciiz "---- Computed with %/s4/d instructions at %/f6/.3f char/insn or %/f8/.1f insn/char.\n\n"

        .text


tb_strlen:
        ## Register Usage
        #
        # $a0: Address of first character of string.
        # $v0: Return value, the length of the string.
        # $a0: Return value, address after string.
        #
        addi $v0, $a0, 1        # Set aside a copy of the string start + 1.
TB_STRLEN_LOOP:
        lbu $t0, 0($a0)           # Load next character in string into $t0
        bne $t0, $0, TB_STRLEN_LOOP  # If it's not zero, continue
        addi $a0, $a0, 1          # Increment address. (Note: Delay slot insn.)

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


        .globl __start
__start:

        mtc0 $0, $22            # Pause tracing.
        addi $s6, $0, 0         # Input number.
        la $s7, test_string     # Address of next string to use.

tb_next_input:

        # Display a message showing input number, text length, and text.
        #
        addi $s6, $s6, 1
        ori $a0, $s7, 0
        jal tb_strlen
        nop
        mtc1 $v0, $f0
        cvt.d.w $f0, $f0         # Convert length to FP now, used later.
        la $a0, msg_in
        addi $v0, $0, 11
        syscall
        nop

        # Call reverse_lists
        #
        ori $a0, $s7, 0
        la $a1, output_string
        la $a2, scratch_storage
        mtc0 $v0, $22           # Resume tracing. (No effect if not stepping.)
        jal reverse_lists
        mfc0 $s5, $9            # Copy current instruction count. (Before.)
        mfc0 $s4, $9            # Copy current instruction count. (After.)
        mtc0 $0, $22            # Pause tracing.
        sub $s4, $s4, $s5       # Compute number of instructions executed ..
        addi $s4, $s4, -1       # .. correcting for the post-return instruction.

        mtc1 $s4, $f4           # Move number of instructions to FP regs and ..
        cvt.d.w $f4, $f4        # .. convert to FP double and then
        div.d $f6, $f0, $f4     # .. compute execution rate in char / insn ..
        div.d $f8, $f4, $f0     # .. and compute insn / char.

        # Compute string showing positions containing errors.
        #
        la $s1, output_string
        la $t0, correct_string_start
        la $t1, test_string
        sub $t1, $s7, $t1           # Offset of current string.
        add $t0, $t0, $t1           # Address of correct string.
        la $t2, error_mask_string
        ori $t5, $0, 32   # ASCII space
        ori $t6, $0, 120  # ASCII x (lower-case ex)
tb_mask_loop:
        lb $t3, 0($s1)
        lb $t4, 0($t0)
        beq $t3, $t4, tb_okay
        sb $t5, 0($t2)
        sb $t6, 0($t2)
tb_okay:
        addi $s1, $s1, 1
        addi $t0, $t0, 1
        bne $t4, $0, tb_mask_loop
        addi $t2, $t2, 1

        sb $0, 0($t2)

        # Show reverse_lists output, error string, and performance numbers.
        #
        la $t0, error_mask_string
        la $s1, output_string
        la $a0, msg_out
        
        addi $v0, $0, 11
        syscall
        nop

        # Move to next test string
        #
        ori $a0, $s7, 0
        jal tb_strlen
        nop
        ori $s7, $a0, 0
        la $t0, test_string_end
        sub $t0, $t0, $s7
        bgtz $t0, tb_next_input
        nop

        ori $v0, $0, 10
        syscall
        nop