################################################################################
##
## LSU EE 4720 Fall 2007 Homework 1
##
##
 ## Due Monday, 17 September 2007

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

 ## Instructions:
  #
  # (0) Read and follow account setup instructions at
  #     http://www.ece.lsu.edu/ee4720/proc.html
  #
  # (1) Copy this assignment, local path name
  #     /home/classes/ee4720/com/s/hw1.s, to a directory ~/hw in your
  #     class account. (~ is your home directory.)  Use this file for your
  #     solution.  The TA-bot will look first for a file named ~/hw/hw1.s.
  #     If you have multiple versions make sure the one you want graded
  #     is in ~/hw/hw1.s.
  #
  # (2) Find the problem in this file and solve it.
  #
  #     A procedure shell has been provided for the problem.  Place
  #     your solution there.
  #
  #     Assembler code following the problems runs your solutions.
  #     That code can be modified.
  #
  #     Please test your code with the demo routine. (Press f9.)
  #     Make sure it works correctly.
  #
  #     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.)
  #      http://www.ece.lsu.edu/ee4720/mips32v2.pdf
  #      Note: SPIM implements MIPS-I instructions.
  #
  # SPIM Documentation:
  #      Appendix A of Patterson and Hennessey.
  #      http://www.ece.lsu.edu/3755/spim.pdf
  #
  # Account Setup and Emacs (Text Editor) Instructions
  #      http://www.ece.lsu.edu/ee4720/proc.html
  #      To learn Emacs look for and follow instructions for the Emacs tutorial.
  #
  # Unix Help
  #      http://www.ece.lsu.edu/v/4ltrwrd/


 ## Note on SPIM
#
# Clicking the close button (usually the upper-right-hand button on
# the window frame) of any window will immediately exit SPIM.
#

 ## Troubleshooting
#
# Make sure that the "run" dialog box shows 0x0400000 for the starting
# address.  If not, __start was not properly defined, possibly due to
# an error before __start.
#
# Check the messages (bottommost) pane for syntax and other errors.  It
# may be necessary to shorten other panes to make the messages pane visible.
# Common syntax errors include using "addi" instead of "add", or vice versa.
# Another common error is mistyping a label in a branch or jump target.
#
# Check the "Text Segments" pane to make sure all of your program is there.
# If not, there may have been an error reading the program.
#
# If your program fails a test or otherwise does not produce the
# expected output modify the test code so that the particular test it
# fails comes first (if it's not already).  Then, single-step the code
# (using the "step") button until you find the problem.
#
# If you've hit a wall ask the instructor help.  It's better to
# err on the side of too many questions than too few.


################################################################################
## Problem 0

# Do the setup described in the instructions above.
#
# Before making any changes to this file (other than comments) run
# the assembler/simulator SPIM using the following steps:
#
#  Load this file into an Emacs buffer using the class-account Emacs.
#
#  If setup was done correctly comments should be red, "Problem 0" above
#  should be in a black, bold, sans-serif font and the assembler below
#  should look something like fruit salad, with pale blue mnemonics,
#  italicized pseudo instructions, purple assembler directives, green
#  line labels, etc.
#
#  Start the SPIM assembler/simulator by pressing [F9].
#    -> A window entitled "xspim" should pop up.  The top pane should show
#       register values, the next pane should have buttons, the third
#       should show the program in binary and assembler forms, the fourth
#       pane shows the data area, and the bottom pane (which might extend
#       past the bottom of the screen) shows messages.
#
#  Run the program by clicking the "run" button then clicking "ok" on the
#  dialog box that pops up.
#    -> A window entitled "SPIM Console" should pop up, the window
#       should be asking you to include your name in this file.  After
#       a name is entered and Spim is re-run it should show four wrong
#       conversions (for Problem 1).  For Problem 0 that's success!!!
#
#  Put your name at the top of the file then run the code in this
#  file.
#    -> The output window of the simulator (which might be hidden
#       behind the main window) should show that the output of the unpack
#       routine is "Not yet implemented." and is not the correct output.




################################################################################
## Problem 1

# The itox routine below is to convert an unsigned 32-bit integer into
# an ASCII string of its radix-R representation, where R is any
# positive power of 2. (For example, if R is 2 convert to binary, if R
# 16 convert to hexadecimal.) But wait, itox is not just any
# integer-to-string program. With itox the caller specifies the digit
# set to use. For example, when converting 5 to binary one might
# specify digit set "01" (resulting in the usual "101") or one might
# choose digit set "ft" (resulting in "tft").

# The itox routine is called with three arguments, in $a0, $a1, and $a2.

# Register $a0 holds the unsigned 32-bit integer to convert.

# Register $a1 holds the address of the digit set, a null-terminated
# string. The character at address $a1 is the digit for zero, the
# character at address $a1 + 1 is the digit for one, and so on.

# Register $a2 holds the address at which the converted string
# is to be written.

# If the number of digits in the digit set is not a power of 2 then
# itox should write a 0 at $a2 (in effect returning a zero-length
# string). Otherwise, it should write, starting at $a2, the radix-R
# representation of $a0 using the digit set provided.

# Complete the itox routine so that it behaves as described above.



################################################################################
## itox -- Convert unsigned integer to custom ASCII string.

        ## Register Usage
        #
        # $a0: Procedure call argument.
        #      Value to convert, an unsigned integer.
        #
        # $a1: Procedure call argument.
        #      Address of digit string.
        #
        # $a2: Procedure call argument.
        #      Place to put converted string.
        #
        # There is no return value, instead the string should be written
        # into the memory at $a2.

        # [ ] Do not modify registers s0-s7
        # [ ] Can modify registers a0-a3, t0-t9.

        # [ ] Return a zero-length string if number of digits not a power of 2.
        # [ ] Make sure digits are in correct order.

        # [ ] DO NOT use division or modulo instructions, instead shift & mask.

        # [ ] The routine must be reasonably efficient.
        # [ ] Fill as many delay slots as possible.

        # [ ] Solutions with syntax errors will get low grades.

        .text
itox:

        ## SOLUTION.

        addi $t7, $a2, 0
        addi $t0, $a1, 0

        # Count number of digits.
        #
lenloop:
        lb $t1, 0($t0)
        bne $t1, $0, lenloop
        addi $t0, $t0, 1

        sub $t1, $t0, $a1
        addi $t1, $t1, -1  # $t1 holds number of digits.


        # Find log base 2 of the number of digits.
        #
        addi $t2, $0, 1    # Used as constant.
        addi $t3, $0, 0    # Log_2 of length.
lgloop:
        sllv $t4, $t2, $t3
        slt $t5, $t4, $t1
        bne $t5, $0, lgloop
        add $t3, $t3, $t5

        # If number of digits not a power of 2 return empty string.
        #
        beq $t4, $t1, ispot
        sb $0, 0($a2)
        jr $ra
        nop

ispot:
        addi $t2, $t1, -1  # Mask for extracting low bits.


        # Convert number to ASCII string. String will be reversed.
        #
loop:
        and $t6, $a0, $t2  # Mask off low bits.
        add $t6, $a1, $t6  # Compute address of digit character.
        lb $t6, 0($t6)     # Load character...
        sb $t6, 0($a2)     # ... and store it in result string.
        srlv $a0, $a0, $t3
        bne $a0, $0 loop
        addi $a2, $a2, 1

        sb $0, 0($a2)

        # Reverse the result string by swapping the first and last
        # character, the second and penultimate character, etc.
        #
        addi $a2, $a2, -1
rloop:
        lb $t0, 0($a2)
        lb $t1, 0($t7)
        sb $t1, 0($a2)
        sb $t0, 0($t7)
        addi $t7, $t7, 1
        addi $a2, $a2, -1
        slt $t2, $a2, $t7
        beq $t2, $0 rloop
        nop

        jr $ra
        nop



################################################################################
## Demonstration and Test Routine

# This routine calls itox on sample numbers, and displays the original
# and converted numbers.

# It's okay to change the code below if that will help you debug your code,
# but your code should work on the original test routine and for other
# valid inputs.



        .data         # Indicate to the assembler that the stuff below is data.


#
# Message displayed if student's name omitted.
#
who_are_you:
        .asciiz "Please put your name at the top of the file where indicated."

#
# Integer values to be converted.
#
values:  # Assembler converts "values" to address of stuff below.
        .word 0x0    # Assembler places zero in memory after label "values".
        .word 0xe
        .word 0x1234abcd
        .word -1              # Mark end of list.
#
# Digit strings to be used when converting the numbers above.
#
digits:
        .asciiz "0123456789abcdef"  # Ordinary hex digits.
        .asciiz "oltefsif%^@;()>+"  # Use bizarre letters for hex.
        .asciiz "01"                # Ordinary binary.
        .asciiz "FT"                # False / True.
        .asciiz "nesw"              # Base four (north, east, south, west)
        .asciiz ""                  # Mark end of list.
#
# Message used by demonstration routine.
#
msg:
        .asciiz "HEX VAL 0x%/s3/08x  CUSTOM VAL %/s2/18s  DIGIT SET %/s1/s\n"
#
# Memory space to be used for result string.
#
str:
        .space 256  # Tell assembler to reserve 256 characters of space.


        .text  # Tell assembler to put stuff below in "text" (program) segment.
        .globl __start
__start:

        la $s0, name
        lb $s0, ($s0)
        bne $s0, $0,  DODEMO
        la $a0, who_are_you
        addi $v0, $0, 11
        syscall
        addi $v0, $0, 10
        syscall

DODEMO:

        # Put constant (address of values a few lines above) in register
        # $s0 using pseudo instruction la.
        la $s0, values     # s0: Address of next value to use.
        addi $s4, $0, -1   # s4: Value marking end of value list.

        #
        # Call itox for each pair of value/digit appearing above.
        #

        # Outer loop - iterate over digit sets.
        #
DIGITLOOP:
        la $s1, digits     # s1: Address of next digit set to use.

        # Inner loop - iterate over values.
        #
VALLOOP:
        # Call itox
        #
        lw $a0, 0($s0)     # For call to itox load first value ...
        la $a2, str        # ... address of storage ...
        jal itox
        addi $a1, $s1, 0   # ... and address of digit set to "a" registers.

        # Show results of itox call.
        #
        lw $s3, 0($s0)     # Re-load value (for display).
        la $s2, str        # Load address of converted string (for display).
        la $a0, msg        # Load message.
        addi $v0, $0, 11   # Load code for LSU xspim's printf syscall.
        syscall            # Display results.

MLEN:
        # Find next digit set.
        #
        lb $t0, 0($s1)
        bne $t0, $0, MLEN
        addi $s1, $s1, 1

        lb $t0, 0($s1)
        bne $t0, $0 VALLOOP      # If next digit set not empty, use it.
        lw $t0, 4($s0)           # Load next value.
        bne $t0, $s4 DIGITLOOP   # If next value not end of list, use it.
        addi $s0, $s0, 4

MEXIT:
        addi $v0, $0, 10
        syscall
        nop