CST 250 Lab 6 -- Calculating Isqrt

Lab Description

In this lab, we will calculate isqrt -- the integer square root of an unsigned 32 bit number. It will make use of the function you developed to convert a binary number to an ASCII decimal number -- bin_to_asciidec as well as the is_a_digit function. In this lab, as in the last lab, you will be required to set up a C-style stack frame in each function that needs one including main.  True C-style stack frames may have sections for saving registers (ra, fp, s and t registers (as needed)), local variable storage, and parameter space. Remember that each stack section will not be needed in every case.  In particular, note that since you are writing in assembly rather than emulating a C compiler, you can (and should) choose to keep most "local variables" in registers rather than setting them up on the stack (unless we run out of registers).  It is likely that we won't need local variables sections in this lab.  True C-style stack frames would reserve space for a0 -- a3 if the function called any others but you don't need to do this in this lab. You also don't need to align stack frame section addresses to multiples of 8 (as was done in the homework). 
   
Isqrt
The integer square root of a positive integer n is the positive integer m which is the greatest integer less than or equal to the square root of n.  Expressed as a formula it is:
isqrt(n) = floor(sqrt(n))
Also, if  m = isqrt(n), then m2 <= n and (m+1)2 > n.
For example, isqrt(253) = 15 because 152 = 225 and 162 = 256

It can be computed iteratively for values of n > 2 as illustrated in the following pseudo code:

guess = (n)/2;
do {
prev_guess = guess;
guess = 1/2 (prev_guess + n /prev_guess);

} while (prev_guess - guess > 1);

We start out with an intial guess, and then refine out guesses until the new guess and the previous guess are within 1 of each other. Mathematicians say that the guesses will converge to isqrt "quadratically" which basically means we don't have to do the refinement too many times to get our answer.
Notes:

Program Considerations:

The unsigned value n we want to find the isqrt of will be "input" as an .asciiz string in the .data segment. The output, presented through the UART1 Output window (as we did in the last lab) will be as follows (assuming n is 253) :

debug iteration: 1 guess: 126
debug iteration: 2 guess: 64
debug iteration: 3 guess: 33
debug iteration: 4 guess: 20
debug iteration: 5 guess: 16
debug iteration: 6 guess: 15
The isqrt of 253 is 15. Check: 15^2 = 225, 16^2 = 256.

Note that the debug iteration lines shown above will be produced from within the Isqrt function. But, the final line of output will come from the main routine.
 
Required functions:

Function bin_to_asciidec:
This function was developed in Lab 4 and used in Lab 5 and it will be used again here. It accepts as arguments a 32-bit unsigned decimal value (a0), and a pointer to an 11 byte space in the .data segment (a1) where the ascii string representation of the value in a0 will be placed.

Function asciidec_to_bin:
This will be a new function written for this lab. It converts a value represented by a string of ascii decimal digits to a binary value. The address of the string will be passed through a0 and the 32-bit binary value returned through v0. This function will be needed to convert the input value from an ascii string to an unsigned binary value. You are required to have this function call the is_a_digit function (developed in Lab 3 and used in Lab 5) to check that each of the ascii characters in the string are valid digits (0 through 9 characters) and get each digit's binary value. Then you can use Horner's method (presented in class) to convert the individual digits to the final binary value. There are several possible error cases:
Note that you should just count the digits as you go through the process of converting the string to binary rather than counting the string length first and then later doing the conversion. 
The main routine should also output appropriate error messages in the case errno is non-zero when asciidec_to_bin returns.  Note that you will have to setup errno in the .data segment, and follow the C convention on errno, which is that main should set errno to 0 before calling any routine that can change its value.

Function isqrt:
This is also a new function written for this lab. It computes the isqrt of the 32 bit unsigned integer value passed through a0 and returns the 32-bit unsigned result through v0.

Function output_string:
This function was defined and the code for it was provided in Lab 4 (also used in Lab 5). Also remember to include the code needed to initialize UART1 in your main routine.

Make sure that all functions (including main) that need stack frames have appropriate stack frames and that they follow the calling convention with respect to preserved and non-preserved registers. 

Procedure:
It is always a good idea to build and test functionality incrementally. so for example, you might write and test the asciidec_to_bin function before writing isqrt (or vice-versa).

Calling Convention
Remember to always follow the calling convention. This is the first lab in which you are writing functions that call other functions.  Only pass parameters to functions using a0 -- a3 and return values using v0 (other than the exception for errno).  Called functions can freely modify call-scratch registers (t0 -- t9, a0 -- a4, v0, v1) without having to save and restore them.  Routines should normally use the call-preserved registers s0 -- s7 for live values that need to be preserved across call(s). (Note that not all values in a routine will need to be preserved across a call, and call-scratch registers are fine for this purpose.)  A subroutine that uses any call-preserved (s) registers needs to save them on the stack at the beginning of the subroutine and restore them at the end. Write functions so that they could be used by someone else who understands the calling convention and what is passed and returned (i.e, the functions could be placed in a library).

Deliverables: