################################################################################
##
## Solution to LSU EE 3755 Fall 2001 Homework 4
##

 ## Name:

 ## Instructions:
  #
  # Copy this to a file named hw04sol.s to directory ~/hw in your
  # class account. (~ is your home directory.)  Use this file for your
  # solution.
  #
  # Procedure shells have been provided for each problem.  Place
  # your solution within the respective shells.
  #
  # The code at the top runs a test on each problem.  That code
  # code can be modified, for example, only calling the test
  # for the problem currently being worked on.
  #
  # Your entire solution should be in this file.  The solution to
  # Problem 0 is not being collected.
  #
  # 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.)

  # Assignment: http://www.ece.lsu.edu/ee3755/2001f/hw04.pdf


################################################################################
## Main Routine


        .text
        .globl __start
__start:
        jal test_countlz   # Comment out this line to skip this test.
        nop
        jal test_itos      # Comment out this line to skip this test.
        nop
DONE:
        addi $v0, $0, 10   # Code for the exit system call.
        syscall
        nop



################################################################################
## Solution to Problem 1

        .globl countlz
countlz:

        ## Register Usage
        #
        # $a0:  Input value.  (Modified by this routine.)
        # $v0:  Return value.

        addi $v0, $0, 33
CLZ_LOOP:
        addi $v0, $v0, -1
        bne $a0, $0, CLZ_LOOP
        srl $a0, $a0, 1
        jr $ra
        nop


################################################################################
## Solution to Problem 2

        .globl itos
itos:

        ## Register Usage
        #
        # $a0: i: Input value, the integer to convert.
        # $v0:    Return value, $a0 value in IEEE 754 format.
        #         Holds return value while "under construction."
        # $t0:    Sign bit.
        # $t1:    Number of leading zeros in absolute value of i.
        # $t2:    Exponent.

        bne $a0, $0, ITOS_NONZERO
        nop
        jr $ra                # Return zero if integer is zero.
        add $v0, $0, $0
ITOS_NONZERO:
        bgez $a0, ITOS_ABS
        slt $t0, $a0, $0      # t0 -> sign of integer.
        sub $a0, $0, $a0
ITOS_ABS:
        clz $t1, $a0          # t1 -> number of leading zeros.
        sllv $v0, $a0, $t1
        sll $v0, $v0, 1
        srl $v0, $v0, 9       # v0 -> significand
        addi $t2, $0, 158
        sub $t2, $t2, $t1     # t2 -> Biased exponent in bits 7:0
        sll $t2, $t2, 23      # t2 -> Biased exponent in bits 30:23
        or $v0, $v0, $t2      # v0 -> biased exponent, significand
        sll $t0, $t0, 31      # t0 -> Sign bit at bit 31
        jr $ra
        or $v0, $v0, $t0      # v0 -> sign bit, biased exponent, significand



################################################################################
## Test Code for countlz

        .data
clzt_data:
        # Test numbers for countlz.  Additional tests can be added.
        # Zero can only appear as the last number.
        .word 0x1, 0xf, 0xfab, 0x72345678, 0x8fffffff
        .word 0
clzt_pass_msg:
        .asciiz "All countlz tests passed.\n"
clzt_fail_msg:
        .ascii  "Test countlz failed. "
        .asciiz "Number in $a1, $t1 (correct) != $t2 (wrong)\n"
clzt_fail_fmt:
        .ascii  "Test countlz failed. "
        .asciiz "Number 0x%/s1/x: lz %/t1/d (correct) != %/t2/d (wrong)\n"

        .text
        .globl test_countlz
test_countlz:
        addi $sp, $sp, -16
        sw $ra, 12($sp)
        sw $s2, 8($sp)
        sw $s1, 4($sp)
        sw $s0, 0($sp)
        la $s0, clzt_data
        add $s2, $0, $0
CLZT_LOOP:
        lw $a0, 0($s0)
        jal countlz
        add $s1, $a0, $0
        clz $t1, $s1
        bne $t1, $v0 CLZT_FAIL
        addi $s0, $s0, 4
        bne $s1, $0, CLZT_LOOP
        nop
        la $a0, clzt_pass_msg
        j CLZT_MSG
        nop
CLZT_FAIL:
        la $a0, clzt_fail_fmt
        add $t2, $v0, $0
CLZT_MSG:
        li $v0, 11
        syscall
        lw $ra, 12($sp)
        lw $s2, 8($sp)
        lw $s1, 4($sp)
        lw $s0, 0($sp)
        jr $ra
        addi $sp, $sp, 16


################################################################################
## Test Code for itos

        .data
itost_data:
        # Test numbers for countlz.  Additional tests can be added.
        # Zero can only appear as the last number.
        .word 1, -1, 2, -2, 5, -5, 3755, -3755
        .word 2123456789, -2123456789
        .word 0x100fffff, 0x1fffffff, 0x1abcdef
        .word 0
itost_pass_msg:
        .asciiz "All itos tests passed.\n"
itost_fail_msg:
        .ascii  "Test itos failed. "
        .asciiz "Integer in $t3, $t1 (correct) != $t2 (wrong)\n"
itost_fail_fmt:
        .ascii  "Test itos failed. "
        .ascii  "Integer %/t3/d, 0x%/t1/08x (correct) != 0x%/t2/08x (wrong)\n"
        .asciiz "                  FP:     %/f0/.f (correct) != %/f2/.f (wrong)\n"


        .text
        .globl test_itos
test_itos:
        addi $sp, $sp, -16
        sw $ra, 12($sp)
        sw $s2, 8($sp)
        sw $s1, 4($sp)
        sw $s0, 0($sp)
        la $s0, itost_data
        add $s2, $0, $0
ITOST_LOOP:
        lw $a0, 0($s0)
        jal itos
        add $s1, $a0, $0
        bgez $s1, ITOST_POS_1
        add $s2, $0, $s1
        sub $s2, $0, $s1
ITOST_POS_1:
        clz $t0, $s2
        sllv $s2, $s2, $t0
        srl $s2, $s2, 8
        sll $s2, $s2, 8
        bgez $s1, ITOST_POS_2
        srlv $s2, $s2, $t0
        sub $s2, $0, $s2
ITOST_POS_2:
        mtc1 $s2, $f0
        cvt.s.w $f0, $f0
        mfc1 $t1, $f0
        bne $t1, $v0 ITOST_FAIL
        addi $s0, $s0, 4
        bne $s1, $0, ITOST_LOOP
        nop
        la $a0, itost_pass_msg
        j ITOST_MSG
        nop

ITOST_FAIL:
        la $a0, itost_fail_fmt
        add $t2, $v0, $0
        add $t3, $s1, $0
        mtc1 $v0, $f2
        cvt.d.s $f2, $f2
        cvt.d.s $f0, $f0
ITOST_MSG:
        li $v0, 11
        syscall
        lw $ra, 12($sp)
        lw $s2, 8($sp)
        lw $s1, 4($sp)
        lw $s0, 0($sp)
        jr $ra
        addi $sp, $sp, 16