CSE 378 Homework 2

Due: Wednesday 1/21/03


Work in pairs. If we know you don't have a pair, information about your new pair will be sent to you shortly.

Purpose

The purpose of this homework is to familiarize yourself with the Cebollita toolset. There are two main steps:
  1. Get everything set up and verify that it works.

  2. Learn about the assembler, linker, simulator, and miscellaneous tools provided by the toolset. You'll use the assembler and linker to build executables, and then use the simulator to run/debug them. You will also try your hand at a little assembly programming by making minor modifications to a program we provide. Finally, you'll use the Cebollita compiler to write/modify your first C-- program.

Part 1: Getting Everything Set Up

The first step is to make sure you have all the software you need, and that you've correctly made a few settings that are required for the software to run. This is an absolutely essential first step, and to emphasize that there's no point going further until it's done, it's described on a separate page.

Part 2: Some Cebollita Programming

Introduction

For this assignment we'll use the following program, which computes the factorial of 9. The line numbers you see are for reference only, and are not part of the actual assembly program.
 1   # compute the factorial of 9 using the following algorithm
 2   #   N = 9
 3   #   result = 1
 4   #   while (N != 0) {
 5   #     result = result * N
 6   #     N = N - 1
 7   #   }
 8
 9   .data                                   # begin data section
10   N:      .word    9                      # reserve and initialize a word
11   result: .space   4                      # reserve but don't initalize a word
12   msg:    .asciiz  "The factorial is: "   # message string
13
14   .text                                   # begin program text
15           .global main
16   main:
17           addi    $t0, $0, 1              # $t0 will hold result, initially 1
18           lw      $t1, N($gp)             # $t1 will hold N, initially 9
19
20   top:    beq    $t1, $0, bottom
21           mult    $t0, $t0, $t1           # result = result * N
22           addi    $t1, $t1, -1            # decrement N
23           j       top                     # goto top
24
25   bottom:
26           sw      $t0, result($gp)        # we'd better save result
27           addi    $v0, $0, 4              # finished w/ loop, now print out
28           addi    $a0, $gp, msg           # message, by invoking syscall 4
29           syscall                         # (print_string)
30
31           addi    $v0, $0, 1              # now print out result, by
32           lw      $a0, result($gp)        # invoking syscall 1 (print_int)
33           syscall
34
35           halt                            # all done
Thankfully, you don't have to type the program in yourself, as you can download it here. Put it in directory Z:\cebollita\apps\myPrograms. Make sure it's called fact.s (not fact.s.txt, as IE will happily try to name it).

Assembling/Linking Your Program

  1. You'll need to build an executable out of fact.s. To do this, you edit file Makefile (in directory cebollita/apps/myPrograms) once:
    Look for the big comment near the top. It's saying you need to add fact to the end of the line just below the block of comments. Do that.

  2. Now you need to do this, once:
    In a cygwin shell, in the directory Z:\cebollita\apps\myPrograms, say make for-standalone

  3. Each time you want re-assemble and re-link your program, in the cygwin shell say make fact.

  4. Each time you want to run your program, say cebsim fact.exe.

What Did You Just Do?

  1. make is a program that saves you some typing by taking lines from a file, called Makefile, and essentially typing them for you when you ask. Step 1 above is a simple modification required so that make knows what to type to build fact.s into fact.exe.

  2. For a program to run, it has to be linked with a prologue and a runtime library. In Cebollita, there are a number of different choices for each, depending on the machine environment you want to simulate. You could specify the prologue and runtime library each time you build the .exe file, but that gets tedious when you're debugging and have to build a large number of times.

    In Step 2 above you're saying you want no prologue and no runtime libary -- you're going to run standalone. That information is put into a (hidden) file, named .cebenv.mk, in the current directory, and is taken from there each time the program has to be linked.

  3. Each time you want to assemble and link fact.s you could type the following by hand:
    cebasm fact.s
    ceblink --output fact.exe [prologue file] [runtime libary file] fact.o
    make is a program that types these things for you. The command issued in step 3 above (after doing steps 1 and 2) (a) lets make figure out that it needs to issue those commands, and (b) tells make the names of the prologue and runtime library files to use.

  4. The fourth step invokes the graphical debugger, which in turn invokes the Cebollita simulator. File fact.exe is loaded into memory, and the machine is waiting for you to do something.

Look at the .o and .exe Files

Cebollita provides tools that will "dump" .o and .exe files -- print them for you. They're binary files, not characters, so you can't just print them in the normal way.

Try them out:

cebdumpm fact.o
cebdumpe face.exe

Using the Simulator: Instructions and Questions

  1. You'll first want to read over the document, Cebollita MIPS Simulator. Note that that document doesn't know about the aliases you established (like cebsim) and so writes things out the hard way.

  2. Start the simulator (cebsim fact.exe ought to do it), and single-step through it.

  3. Complete the following table by examining various registers and memory location contents after the appropriate instructions are executed. Using the breakpoint command may help in certain situations.

    Location Line 18 Line 22
    3rd iteration
    Line 22
    5th iteration
    Line 22
    8th iteration
    Line 26
    $t0




    $t1




    result($gp)




  4. In total, how many instructions (in the simulator) are executed to calculate the factorial of 9? The right way to answer this question is not to step the program through 9 loops and count instructions, but rather determine how many instructions are exectuted before the loop, during one iteration of the loop, and after the loop. Then you can give us an answer in terms of N, where N is the value we're calculating the factorial of (as well as the number of times the loop iterates).
     
    
    
    

  5. Did you answer 4 already? Turns out the simulator prints out some useful information in the console window when you're done simulating...

Assembly Programming: Modifications

Modify the given code so that it reads a value of N from the user, and then computes its factorial. Do this by reading the simulator user's manual (above), as well as Appendix A, to figure out how to make the appropriate syscall. Next, modify the program to continue prompting the user for values of N and computing their factorials. Exit the program when the user enters a negative number.

Compilers

The Cebollita toolkit provides a compiler for a subset of the C language (we call it C--). Below is the C-- version of the factorial program. It can be found here. Copy the program to your home directory; transform it into an executable and then use the simulator to execute it.
main() {
  int N = 9;
  int result = 1;
  while (N != 0) {
    result = result * N;
    N = N - 1;
  }
  printString("The factorial is: ");
  printInt(result);
}
(Technically, this is a little different because it doesn't do a Halt - it does something similar, though.)
  1. Edit the Makefile to add hw2 to that famous line.
  2. C-- programs are most naturally written using both a prologue and a runtime libary. Say make for-os to arrange for the right ones to be used.
  3. Now compile/assemble/link hw2.c to produce hw2.exe: make hw2.
  4. Now run hw2.exe: cebsim hw2.exe. Hopefully, you'll get the same result as above.
Answer the following questions. How many cycles does it take? How many load instructions are executed by the program? How many arithmetic instructions are executed?






Finally, modify the above C-- program in the same manner as you modified the assembly program (above). It should call the function readInt to get an integer from the user. Below is an example C-- program that uses readInt:
main() {
  printString("Please enter a number: ");
  int x = readInt();
  if (x < 0) {
    printString("Your number is negative.\n");
  }
  else {
    printString("Your number is non-negative.\n");
  }
}
Contrast the tradeoffs between programming in C-- and assembly code. How long did it take you to make the respective modifications?

Turn-in

Please turnin your modified assembly program, your modified C-- program, your Makefile, and a file with the answers to the questions above.