CS 354, version B
Fall 2008
Name:___________________
ID:___________________
Exam 2
No electronic devices may be used while taking this exam. Examples of devices not allowed are calculators, pagers, cell phones, wrist calculators/computers, laptop computers, pocket computers. Each student is allowed one 8.5 by 11 inch sheet of paper with handwritten notes. The notes may be on both sides of the paper.

Show all work, and do any/all calculations on the exam. Extra scratch paper may not be used.

The end of the exam has a table of MAL instructions.

Exam Score
Q1 = _____ /   8
Q2 = _____ /   8
Q3 = _____ / 12
Q4 = _____ / 12
Q5 = _____ / 10
Total = _____ / 50



Question 1 (8 points )
Consider a 3-dimensional integer array A[3][4][2] where the first index goes from 0 to 2, the second from 0 to 3, and third from 0 to 1. Assume that array begins at address 200 and elements are stored in the following order: is A[0][0][0], A[0][0][1], A[0][1][0], A[0][1][1], A[0][2][0], ....

(a) What is the total size of the array in bytes?
4 * 3 * 4 * 2 = 96 bytes


(b) What is the address of element A[2][1][1]?
276 = 200 + 4*(2*4*2 + 2*1 + 1)


Question 2 (8 points)
Most instruction sets, such as MIPS, use byte addressing and store words in four bytes. Consider the following data declarations.

	.data
prompt: .asciiz "Hi!"
   foo: .word 0x61626364   # ASCII 'a' 'b' 'c' 'd'
   bar: .word 0x65666768   # ASCII 'e' 'f' 'g' 'h'

(a) If the assembler begins prompt at address 256 and stores foo and bar immediately after, what addresses would foo and bar get assigned?
foo is at 260
bar is at 264

(b) How do Little Endian and Big Endian instruction sets differ on storing foo?
One endianess will store 0x61 at 260, 0x62 at 261, 0x63 at 262, & 0x64 at 263,
while the other endianess will store 0x64 at 260, 0x63 at 261, 0x62 at 262, & 0x61 at 263.




Question 3 (12 points)
Consider implementing a first-come-first-serve (FIFO) queue using an array:

myqueue:  .word 0:8
and initialized as follows:
# $7 qstart == first location
# $8 head == 1st full location unless head==tail
# $9 tail == 1st empty location
# $10 qend == after last location

      la $7, myqueue  
      la $8, myqueue
      la $9, myqueue
      add $10, $7, 32

Consider this code for enqueuing:

      sw $13, ($9)      # assume incoming data in $13
      add $9, $9, 4
      # add more code here

      bne $9, $10, enq_nowrap
      move $9, $7
enq_nowrap:
and this code for dequeueing:
      lw $13, ($8)     # assume outgoing data for $13
      add $8, $8, 4
      # add more code here

      bne $8, $10, deq_nowrap
      move $8, $7
deq_nowrap:
 
(a) (8 points) One reason the above queue is not correct is that, as items are enqueued and dequeued, the head and tail pointers will keep increasing and point to memory locations after the end of the myqueue array. A solution to this is to make the queue wrap around back to the top once it reaches the end. Add MAL code in the space provided above to keep queue items in myqueue.

(b) (4 points) Use words to describe other reason(s) why the above queue implementation is not correct. Hint: think of error conditions.
When the queue is full, enqueue should report an overflow error rather than overwriting an element.
When the queue is empty, dequeue should report an underflow error rather than return an incorrect element.

Question 4 (12 points)
Implement the follow C code in MAL. We have provided the first three instructions.

#
# for (i = 1, sum = 0; i <= 10; i++) {
#       if (i%2==0) {           /* i is even */
#               sum -= i;
#       }
#       else {                 /* i is odd */
#               sum += i;
#       }
#  }
#
# Use $8 for i, $9 for sum, $10-$25 for any temporary variiables

        li $8, 1

        li $9, 0
	
        li $10, 10   # loop bound

my_for: bgt $8, $10, end_for
        rem $11, $8, 2 # i%2
        bnez $11, my_else
        sub $9, $9, $8
        b my_for2
my_else: add $9, $9, $8
my_for2: add $8, $8, 1
        b my_for
end_for:


















The exam continues on the next page ....


Question 5 (10 points)
Please complete this factorial function following 354 calling conventions (incoming parameters at lowest addresses in caller's activation record (AR), return value into $v0, and callee activation record must hold return address, callee saved values of $8-$25 used, any temporary memory variables, and outgoing parameters).

# /* n! = n*(n-1)! for n > 0     */
# /* 0! = 1                      */
# /* Example: 4! = 4*3*2*1 = 24  */
# 
# int factorial(int n)
# {
# int ret;
#   if (n==0) ret = 1;
#   else {
#      ret = n*factorial(n-1);
#   }
# return ret;
# }

factorial:
        sub $sp,$sp,16   # allocate factorial's activation record (AR)

        sw  $ra,16($sp)  # save return address

        sw  $8,12($sp)   # callee save of registers $8-$25 used

        sw  $9,8($sp)

        lw  $9,20($sp)   # get 1st parameter n 

        bnez $9, else

        li $8,1          # 0! = 1

        b end_if

else:   sub $8,$9,1      # (n-1)

        sw  $8,4($sp)    # setup outgoing parameter (n-1)

        jal factorial    # call factorial(n-1)

        mul $8,$9,$v0    # multiply w/ incoming return value

end_if: move $v0,$8      # prepare outgoing return value

        lw  $ra,16($sp)  # restore return address

        lw  $8,12($sp)   # callee restore of registers $8-$25 used

        lw  $9,8($sp)

        add $sp,$sp,16   # deallocate factorial's AR

        jr $ra










ADD TABLE OF MAL INTRUCTIONS

http://www.cs.wisc.edu/~markhill/cs354/Fall2008/handouts/MAL.pdf