CS 61CL (Summer 2009)

Project 2

Submit as "proj2".  Due 11:59 pm Friday 7/17/2009.

This is an individual assignment; you must work alone. Submit your solution, a file named snprintf.s, as proj2, using the command.

        submit proj2

on your instructional UNIX account. Don't submit anything to Expertiza for this project.

Goals

This project should give you more practice with representation of data types, in particular, working with how they are passed as arguments on a MIPS processor. It will also give you more experience with MIPS assembly language programming.

Getting started

Make a directory named proj2 in your home directory. Then copy the file ~cs61c-th/snprintf.s to the directory; this is a main program that includes several calls to snprintf, and into which you should put your code.

Note carefully the line below which all your changes must be made. Do not make any changes above that line. Our autograder will strip off that segment of code and replace it by other test calls.

snprintf

You are to provide a MIPS assembly language implementation of the C function snprintf:

    int snprintf (char *outbuf, size_t outbufsize, char *format, ...)

snprintf is similar to printf, except that it writes to the first argument, the string outbuf, instead of to standard output (the screen). A terminating null character ('\0') is written to outbuf prior to return from snprintf. The second argument specifies the size of the output buffer referred to by outbuf, in bytes (we will be using ASCII for this project so 1 byte = 1 character). The third argument is the format string, much like printf's.

Some special cases:

Arguments

Your function must accept any number of arguments, passed according to MIPS standard conventions: If there are more than four arguments, the additional ones will be spilled to the stack, with the first "spilled" argument in the lowest stack position. (This means the address closer to zero.)

Return

More details about arguments

Since there can be an arbitrary number of arguments to the snprintf function, all arguments after the fourth (if they exist) will be passed on the stack. Before your function is called, the caller will save any extra 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 your code moves the stack).

If this is at all confusing to you, please read this tutorial on MIPS stack management with more detailed information and nifty diagrams.

What you need to do

Within snprintf.s, you will be implementing format specifiers that differ slightly from those in the ANSI snprintf. The ones you are to implement are listed below. All are case-sensitive.

What you don't need to do

Handling error cases

The ANSI standard notes that for various error cases, snprintf's behavior is undefined. Listed below are some error cases, along with how you should handle them for this project.

Error case How to handle it
The output buffer is null. Return 0.
The format string is null. Return 0 without changing the output buffer.
The number of characters to print is greater than the output buffer size minus 1. Discard extra characters.
The format string contains occurrences of '%' followed by a character that's not one of 'd', 'u', 'x', 'c', 's', or '%'. Copy the unrecognized character to the output buffer ("%z" becomes "z").
The string argument corresponding to a "%s" in the format string is null. Copy nothing to the output buffer for that format specifier.

You may assume that there at least as many things to print as there are format specifiers. It would be nice to be able to test this, but it isn't possible. (Hint: you'll soon see why.)

Things to keep in mind

Testing

You should consider writing a complete set of test cases as part of your solution. Building these test cases as you add functionality will allow to quickly verify that any new functionality has not broken your old functionality. Consider automating these tests as much as possible to save yourself time in the long run. We will post the highlights of our autograder tests once they are finished.

Project Tips

Project 2 tips available here

Clarifications and a few more tips

  1. Don't assume that registers are initialized to zero. If your code is crashing when the autograder runs it, this is most likely your problem.
  2. Make sure to obey the register conventions! $s0-$s7, $gp, $fp, and $sp should all be the same when your snprintf function completes.
  3. If you have a jal instruction inside your code, it is not necessary to obey the register conventions inside of your subfunction, though it is certainly good practice. This is because you might want to reuse those subfunctions in some other program someday. If it's a really small subfunction though, it doesn't really matter.
  4. It is bad practice to store information on the stack without moving the stack pointer. You can get away with it on this project, but if you were to call someone else's code, they would end up just overwriting your precious stack information (since you effectively didn't allocate space)
  5. Don't forget about the LB and SB instructions, these will simplify your life considerably when reading and writing bytes at a time.

Site Maintained by: Josh Hug