la $a1, __format1 sw $a1, 4($sp) # 4($sp): __format1
Gain experience with:
Instead of one big, long, crazy project, we're going to do three smaller excercises.
To submit your project, create a directory named proj2 that contains: sprintf.s, div.s and fp.c (You can download these files from the links on this page or copy them from ~cs61c/lib/proj2/). From within that directory, type "submit proj2".
The project deadline is 11:59pm on Friday, 13th October.
Since there can be an arbitrary number of arguments to the sprintf function, all arguments will be passed on the stack instead of in registers $a0-$a3. Before your function is called, the caller will save arguments to the stack in the same way $s0-$s7 registers are saved. (By doing sw $s0, offset($sp)). In order to access these variables, you will need to figure out the correct offset in relation to the callee stack pointer.
For example, if the caller stores an argument in 0($sp), the callee might access the argument at 8($sp), depending on how the stack pointer is moved in the callee function. (NOTE: It is not always an offset of 8, it depends on how the stack is moved)
If this is at all confusing to you, please read this Tutorial on MIPS stack management with more detailed
information and nifty diagrams.
Write a MIPS assembly language implementation of the C function sprintf:
int sprintf (char *outbuf, char *format, ...)
sprintf works like printf, except that it writes to the string outbuf instead of to standard output. outbuf already points to allocated space, that is large enough to hold the string.
Your function must accept any number of arguments, passed according to a non-MIPS standard conventions: All the arguments will be passed through the stack, with the first argument in the lowest stack position (meaning, the address closer to zero. Looking at the figures in the tutorial, this means closer the to top).
What you need to do:
You do not have to implement all of the formatting options of the real sprintf. Here are the ones you are to implement:
What you don't need to do (unless you really want to):
To run this project, you need to load two files in the correct order:
run xspim and load test.sprintf.s. Next load sprintf.s. Finally, run your
program. The following Makefile may make
your life easier.
Implement this division algorithm in MIPS. NOTE: You must use this recursive algorithm. Iterative solutions will receive zero (zip, nothing, nada) points.
Given x and y (in $a0 and $a1), return the quotient (q) and remainder (r) (in $v0 and $v1). You can treat x and y as unsigned.
I know what you're thinking so no, you may not use the div instruction (obviously). The only arithmetic operations you can do are addition, subtraction and bit-shifting.
divide(x, y) if x == 0: return (q, r) = (0, 0) (q, r) = divide( floor(x/2), y ) q = 2 * q r = 2 * r if x is odd: r = r + 1 if r >= y: r = r - y q = q + 1 return (q, r)
Put your code in the framework given in div.s. This is not a not a long problem. It can be done in around 20 lines of MIPS.
Fill in the function:
void fp(unsigned int f)The function should print out a string corresponding to interpreting f as a floating point number using the guidelines below. You may find it useful to add a method that converts decimal numbers to binary numbers. Put your code in the framework in fp.c.
NOTE: Since there was an inconsistency between the spec and example code regarding minimum effort digit formatting, you may do one of two things when printing out the mantissa:
The following table lists all the possibilities:
|Single Precision||Object Represented||What you must write into the buffer|
|0||nonzero||± denormalized number||[-]denorm|
|1-254||anything||± normalized number||[-]mantissa_in_binaryb 2^([-]exponent_in_decimal)|
|255||nonzero||NaN (Not a Number)||[-]NaN|
|Number||Interpreted as floating point|