################################################################################
##
## LSU EE 4720 Fall 2003 Homework 2 Solution
##
##

.data
name:
        .asciiz "David Koppelman"  # Put your name between the quotes.

################################################################################
## Main Routine and Problem 2 Solution

# This routine runs the test code for the first problem.  It also makes
# sure you put your name at the top of the file.  It does not have to
# be modified, but it can be if it would help.  For example, you might
# comment out a test for one of the problems when working on the
# other.

# The comments below are part of the solution to Problem 2.

        .data
who_are_you:
        .asciiz "Please put your name in the top of the file where indicated."
test_data:
        .asciiz "-4"
        .word -4
        .asciiz "123 "
        .word 123
        .asciiz "  3224834 "
        .word 3224834
        .asciiz " - 7912 "
        .word -7912
        .asciiz "X"
msg:
        .asciiz "The value of string %/s4/s returned was  %/t1/d  (%/t2/s).\n"
textc:
        .asciiz "Correct"
textw:
        .asciiz "Wrong"
msgt:
        .asciiz "A total of %/s2/d correct and %/s3/d wrong.";


        .text
        .globl __start
__start:
        #
        # Check if name entered above.
        #
        la $s0, name            # Load address of name.
        lb $s0, ($s0)           # Load first character.
        bne $s0, $0  TESTS      # If it's not null, jump to tests.

        # The pseudo instruction below (la) is in the delay slot of a
        # branch.  This particular pseudo instruction may expand into
        # two machine instructions.  If so, only one of them will
        # execute when the branch is taken.  The [sic] comment is
        # indicating that this was done intentionally, if the branch
        # is taken only half of the pseudo instruction executes but
        # that's okay because the instruction is not needed anyway.
        # ([sic] means "that's not a mistake" or sometimes "that's not my mistake",
        # it is often used to indicate that something unusual is not a typo.)

        la $a0, who_are_you  # [sic]  <- Explain this comment.
        # Line above: Load format string for "missing name" message.
        addi $v0, $0, 11        # Choose system call 11 (printf)
        syscall                 # Print name missing error message.
        addi $v0, $v0, 10       # Choose system call 10 (exit)
        syscall                 # Exit

        #
        # Initialize values used in main loop.
        #
TESTS:
        la $s0, test_data       # Address of beginning of test data.
        addi $s7, $0, -4        # Prepare a mask (0xfffffffc), used for alignment.
        or $s2, $0, $0          # Initialize count of correct conversions to zero.
        andi $s3, $s3, 0        # Initialize count of incorrect conversions to zero.

        #
        # Main Loop:
        #
        #  Load first character of string to convert from data table...
        #  ...check if at end of data table...
        #  ...if not, call atoi...
        #  ...load value of string from data table...
        #  ...compare with atoi return value and update correct/incorrect counters...
        #  ...continue loop.
        #
TLOOP:
        lbu $t0, 0($s0)         # Load first character of string to convert.
        addi $t0, $t0, -88      # Check if it's "X", indicating no more tests.
        beq $t0, $0, TDONE      # If no more tests, exit loop.
        xor $a0, $s0, $0        # Copy address of string to $a0, for called routine.
        jal atoi                # Call conversion routine.
        add $s4, $s0, $0        # Make another copy of address of string.
TEOS:
        lbu $t0, 0($s0)         # Load character from string ...
        bne $t0, $0, TEOS       # ...and exit if end of string found.
        addi $s0, $s0, 1        # Advance to maybe next character of string.

        addi $s0, $s0, 3        # Make data pointer a multiple of 4 by adding 3 ...
        and $s0, $s0, $s7       # ... and then masking with 0xfffffffc. 
        lw $t1, 0($s0)          # Load integer value of string (from aligned addr).
        bne $t1, $v0, TWRONG    # If value returned by atoi is different, error.
        addi $s0, $s0, 4        # Point to next string to convert.
        la $t2, textc           # Load address of "correct" text.
        j TMSG                  # Jump to routine printing outcome message.
        addi $s2, $s2, 1        # Increment correct counter.

TWRONG:
        la $t2, textw           # Load address of "wrong" text.
        addi $s3, $s3, 1        # Increment wrong counter.

TMSG:
        or $t1, $v0, $v0        # Copy return value of atoi. ($v0 needed for syscall)
        addi $v0, $0, 11        # Choose printf syscall.
        la $a0, msg             # Load address of outcome format string for printf.
        syscall                 # Print outcome.

        j TLOOP                 # Try to load another string to convert.
        nop

TDONE:
        addi $v0, $0, 11        # Choose printf syscall.
        la $a0, msgt            # Load address of results summary format string.
        syscall                 # Print results summary.

        addi $v0, $0, 10        # Choose exit syscall.
        syscall                 # Bye.


################################################################################
## Problem 1 Solution Shell

# When the routine below is called register $a0 has the address of a
# null-terminated string, that string is an integer (in ASCII), for
# example, "1", " 23423", " - 71 ".  Note that the integer may be
# negative and that there may be spaces before and after the minus
# sign and digits.  Assume that there are no spaces between digits and
# that only digits, a minus sign, and spaces are in the string.
#
# The routine should place the integer value of that string in
# register $v0, and then return.  Make sure you understand the
# difference between an ASCII string representation of an integer (the
# call argument) and a 32-bit two's complement representation (the
# return value).
#
# When your write your code follow the additional guidelines below.
# If the register use guidelines are not followed the test code might
# not work.  The guidelines on speed and multiplication will be taken
# into account when grading.

atoi:

        ## Register Usage
        #
        # $a0:  Procedure argument: pointer to string.
        # $v0:  Return value: integer corresponding to string.

        # [x] Assume that multiplication takes 7 cycles.
        # [x] Code should run quickly, avoid multiplication if that helps.
              # Used two shifts and an add to avoid multiplication.
        # [x] Can modify registers $a0-$a3, $t0-$t9 and $v0 only.
        # [x] Do not modify $s0-$s7, $sp, $fp, or $ra
        # [x] Fill as many delay slots as possible.


        # Insert solution here.

        addi $t9, $0, 32  # Blank
        addi $t8, $0, 45  # -
        addi $t7, $0, 0   # If non-zero, sign bit present.
        addi $v0, $0, 0

        # First, skip whitespace.

PREDIGIT:
        lbu $t0, 0($a0)         # Load character.
        beq $t0, $0, EXIT       # If end of string, return.
        addi $a0, $a0, 1        # Increment address.
        beq $t0, $t9, PREDIGIT  # If blank, continue loop.
        nop
        beq $t0, $t8, MINUS     # If minus, go to code setting minus flag ...
        nop                     # ... else assume a digit and fall through.

        # At beginning of loop $t0 holds a digit.

DIGITLOOP:
        addi $t0, $t0, -48      # Convert digit from ASCII to an integer.
        sll $t1, $v0, 3         # Multiply value of string (so far)...
        sll $t2, $v0, 1         # ...by 10 using two shifts and an add.
        add $v0, $t1, $t2
        add $v0, $v0, $t0       # Add digit on to value of string.
        lbu $t0, 0($a0)         # Load the next character ...
        beq $t0, $t9, EXIT      # ... if it's blank, exit loop ...
        nop
        bne $t0, $0, DIGITLOOP  # ... if it's not null, continue loop.
        addi $a0, $a0, 1        # Advance to next character.

EXIT:
        beq $t7, $0, RETURN     # If minus sign not found, go to return code.
        nop
        sub $v0, $0, $v0        # Otherwise, negate value.

RETURN:
        jr $ra                  # Do not comment lines like this "return" unless
                                # the code is part of a lesson on return statements.
        nop

MINUS:
        j PREDIGIT              # Remember that a minus sign was encountered.
        addi $t7, $0, 1