#---------------------------------------------------------------------------------- # This program contains 2 procedires: # # div: Perform division arithmetic # # main: Test the division for different numbers # # # #---------------------------------------------------------------------------------- .text #---------------------------------------------------------------------------------- # Procedure name: div # It divides one 32-bit number by another # # # Register allocation # Inputs: # $4 = dividend - the number to divide # $5 = divisor - the number to divide by # Output: # $6 = quotient - the result of the division # $7 = remainder - what remains after the division # $12: 0->divion was a success # 1->Division was a failure # Other registers used # $13 Temporary test register # $14 Temporary register (Tests) # $15 Random testing and "shifts" # $16 dividend_sign # $17 divisor_sign # #---------------------------------------------------------------------------------- # First, cover our tracks with the stack #--------------------------------------------------------------------------------- divi: addi $29, $29, -20 #Decrement stack pointer sw $13, 16($29) #Save $13 for restore on exit (StackE-1) sw $14, 12($29) #Save $14 for restore on exit (StackE-2) sw $15, 8($29) #Save $15 for restore on exit (StackE-3) sw $16, 4($29) #Save $16 for restore on exit (StackE-4) sw $17, 0($29) #Save $17 for restore on exit (StackE-5) #-------------------------------------------------------------------------------- # Check for divide by zero or 0x80000000 # C source code: # if (divisor == 0 || divisor == 0x80000000 || dividend == 0x80000000) # { # return ERROR; # } # #---------------------------------------------------------------------------------- bne $5, $0, div10 #If divisor !=0, proceed with devision j fail #Otherwise, Faliur code and exit division lui $15, 0x8000 #Equivalent to $15=0x8000 0000 bne $5, $15, div10 #If divisor !=0x80000000, proceed with devision j fail #Otherwise, Faliur code and exit division bne $4, $15, div10 #If dividend !=0x80000000, proceed with division j fail #Otherwise, Faliur code and exit division #-------Otherwise, we need to return an error code--------------------------------- fail: addi $12, $0, 1 #Failure code loaded in success register j Exitdiv #Not much more to do but go back to main and share the bad news #---------------------------------------------------------------------------------- # Now that the illegal operation tests are passed we can devide. # # First step: Check and remove signs from dividend and divisor # # C source code: # dividend_sign = 0; # divisor_sign = 0; # # if (dividend < 0) # { # dividend_sign = 1; # dividend = -dividend; # } # # if (divisor < 0) { # divisor_sign = 1; # divisor = -divisor; # } #---------------------------------------------------------------------------------- #---------1st line C code: return SUCCESS;----------------------------------------- div10: addi $12, $0, 0 #loads 0 for success in the "success" register slt $16, $4, $0 #If dividend($4)<0, dividend sign($16)=1 beq $16, $0, div20 #If dividend +, skip the next step sub $4, $0, $4 # 0-(-dividend) = (+dividend) div20: slt $17, $5, $0 #If divisor($5)<0, divisor sign($17)=1 beq $17, $0, div30 #If dividend +, skip the next step sub $5, $0, $5 # 0-(-dividend) = (+dividend) #---------------------------------------------------------------------------------- # initialisation of division # Source C code: # # shifts = 0; # *remainder = dividend; # *quotient = 0; #---------------------------------------------------------------------------------- div30: add $15, $0, $0 #shifts ($15)=0 add $7, $0, $4 #remainder($7) = dividend($4) add $6, $0, $0 #Quotient ($6) = 0 #---------------------------------------------------------------------------------- # Shift divisor until most significant bit is set # Source C code # while ((divisor & 0x40000000) != 0x40000000) { # divisor = divisor << 1; # ++shifts; # } #----------------------------------------------------------------------------------- div40: lui $13, 0x4000 #$13 = 0x40000000 #---To save time on small numbers, cuz this could take a long long time--------- and $14, $4, $13 #We and the dividend with the max value div41: and $14, $13, $5 #Then And divisor with "dividend And max" beq $13, $14, div50 #Once we alligned the most significant bit, we can leave the loop sll $5, $5, 1 #divisor = divisor<<1 addi $15, $15, 1 #Increment Shift counter by 1 j div41 #Jump back to the start of the loop to do the test #------------------------------------------------------------------------------------ # Subtract and shift loop # Source C code # for (i = 0; i <= shifts; ++i) # { # *quotient = *quotient << 1; # if (*remainder - divisor >= 0) # { # *remainder -= divisor; # *quotient += 1; # } # divisor = divisor >> 1; # } #-------------------------------------------------------------------------------------- div50: beq $15, $0, adjquo #Once shift = 0, we and jump out of the loop sll $6, $6, 1 #Quotient = Quotient <<1 sub $13, $7, $5 #$13 = remainder - divisor slt $14, $13, $0 #If remainder - divisor >=0 $14=0 bne $14, $0, div60 #If remainder - divisor <0, skip the next 2 lines sub $7, $7, $5 #remainder = remainder - divisor addi $6, $6, 1 #Quotient +=1 div60: srl $5, $5, 1 #divisor = divisor >>1 addi $15, $15, -1 #Shift is decremented by 1 j div50 #Jump back to the top of the loop #---------------------------------------------------------------------------------- # Restoring the sign on the result # # C source code # if (divisor_sign ^ dividend_sign) # { # *quotient = -*quotient; # } # # if (dividend_sign) # { # *remainder = -*remainder; # } # To be quite honest, i thing your C code is warped #---------------------------------------------------------------------------------- # If the signs were ++ or -- (11 and 00), we dont need to adjust the quotient #---------------------------------------------------------------------------------- adjquo: addi $15, $0, 0 #Set $15=0 xor $15, $16, $17 #If signs were 1 0 xor 0 1, $15=1 beq $15, $0, adjrem #If $15=0, +/+ or -/-, skip next step sub $6, $0, $6 #Flip the sign on the quotient adjrem: beq$16, $0, Exitdiv #if the dividend +, reminader+. Skip next step sub $7, $0, $7 #If dividend-, flip the sign of the remainder #---------Prety much done here. Restore registers and teleport to main-------------- Exitdiv:lw $13, 16($29) #Restores $13 (StackE-1) lw $14, 12($29) #Restores $14 (StackE-2) lw $15, 8($29) #Restores $15 (StackE-3) lw $16, 4($29) #Restores $16 (StackE-4) lw $17, 0($29) #Restores $17 (StackE-5) addi $29, $29, 20 #Reincrement stack pointer to top of stack jr $31 #Go back to main with our precious results #---------------------------------------------------------------------------------- # Procedure Name: Main # # Description: Performs the following tests to div # Divide by 0: 1 / 0 # Divide positive by negative: 9 / -4 # Divide negative by positive: -9 / 4 # Divide negative by negative: -9 / -4 # Use max as dividend: 2147483647 / 4 # Use max as divisor: 4 / 2147483647 # Use min as dividend: -2147483648 / 4 # Use min as divisor: 4 / -214783648 # Divide by 1: 4 / 1 # Divide by -1: 4 / -1 # # Register Allocation: # $4 Dividend # $5 Divisor # $6 Quotient # $7 Remainder # $8 slt for test loop # $9 Dividendt start address # $10 Divisort start address # $12 Division success value # $16 Offset for array access # $17 "i" to access array element # # # #---------------------------------------------------------------------------------- .globl main main: addi $16, $0, 0 #Sets the offset [i] to 0 la $9, Dividendt #Saves address of dividendtestarray[0] in $9 la $10, Divisort #Saves address of start of Divisortestarray[0] in $10 #__________________________________________________________________________________ # C source code # # for (i = 0; i < TESTS; ++i) # { # printf("%d divided by %d ", dividend[i], divisor[i]); # # #---------------------------------------------------------------------------- # First we load and print dividend[i] #---------------------------------------------------------------------------- main10: add $17, $9, $16 #Adds the offset+start adress of dividendarray (sets[i]) lw $4, 0($17) #Loads the ith element of the dividend array li $2, 1 #Code for printing integer syscall #Prints dividend[i] #---------------------------------------------------------------------------- # Since we are forced by the assignment to use $4 for dividend # And we need $4 like a million times for syscall, we save the value # of it on the stack for now #---------------------------------------------------------------------------- addi $29, $29, -4 #Decrements the stack pointer sw $4, 0($29) #Pushes $4 on the stack #---------------------------------------------------------------------------- # Finally we can use syscall with peice of mind :) # We print out "... devided by -divisor[i]-..." #---------------------------------------------------------------------------- la $4, String1 #Pointing to the string " divided by " li $2, 4 #Syscall code for printing strings syscall #Prints out " divided by " add $17, $10, $16 #Adds the offset+start address of the diviser array (sets[i]) lw $5, 0($17) #Loads the ith element of the divisor array add $4, $0, $5 #Pust divisor[i] in $4 for printing li $2, 1 #Code for printing integers syscall #Prints divisor[i] #------------------------------------------------------------------------------ # Now the magic begins! # The computer will devide both munbers # # C code: # result = div32 (dividend[i], divisor[i], "ient, &remainder); # # We will pass on the values $4=dividend[i] and $5=divisor[i] # # #------------------------------------------------------------------------------ lw $4, 0($29) #Restore the dividend to $4, as per assignment requirements addi $29, $29, 4 #Align the pointer with the stack jal divi #Jumps to divi and saves return address #-For some reason SPIM keeps giving me error when i call the functinon div or div32--- #------------------------------------------------------------------------------- # # Now we evaluate the success of the division # Success: # $12: 0->divion was a success # 1->Division was a failure #------------------------------------------------------------------------------- beq $12, $0, main20 #If everything was cool, skip the next part #-----------Otherwise, there was a problem in the division---------------------- la $4, Error #loads the Error string in $4 li $2, 4 #Syscall code for printing strings syscall #Will print out error message #-----------Now we go back to to our for loop------------------------------------ j main30 #-------------------------------------------------------------------------------- # # At this point, everything was cool in the division # All we have left to do is print out the result # C source code: # else # { # printf("is %d remainder %d\n", quotient, remainder); # } # As per assignment requirements, comming from div # $6 Quotient # $7 Remainder # #--------------------------------------------------------------------------------- main20: la $4, Is #Loads the "is" string in $4 li $2, 4 #syscall code for printing strings syscall #Prints out " is " add $4, $6, $0 #Puts the quotient in $4 li $2, 1 #syscall code for printing integers syscall #prints the value of the quotient la $4, Remainder#Loads the string " remainder " in $4 li $2, 4 #siscall for printing out strings syscall #Prints out " remainder " add $4, $7, $0 #The remainder is moved in $4 li $2, 1 #Syscall code for printing integers syscall #Prints out the remainder la $4, Enter #Need to change the line li $2, 4 #Syscall code for printing strings syscall #Equivalent of pressing enter=change line #----------------------------------------------------------------------------------- # This is the end of the "for loop" # i < TESTS; ++i # We increment i by 1 and if i