Assignment 9, due Apr 4

Solutions

Part of the homework for 22C:60 (CS:2630), Spring 2014
by Douglas W. Jones
THE UNIVERSITY OF IOWA Department of Computer Science

On every assignment, write your name legibly as it appears on your University ID card! Homework is due on paper at the start of class on the day indicated (usually Friday). Exceptions will be made only by advance arrangement (excepting "acts of God"). Late work must be turned in to the TA's mailbox (ask the CS receptionist in 14 MLH for help). Never push homework under someone's door!

  1. A small problem: Suppose that R3 and R4 contains the 64-bit value a and R5 and R6 contain another 64-bit value b. (the least significant halves are in R3 and R5). Write Hawk code to perform this assignment:
            a = a + b;
    
            ADD     R3,R3,R5
            ADDC    R4,R6
    

    This only takes a few instructions. (0.5 points)

  2. Background: Suppose that R3 contains a 2's complement value and you perform the following:
            SR      R3,4
    

    You might say you have just divided R3 by 16, and for many purposes, you did. On the other hand, the result may not conform to your intuitive expectation for division by 16.

    a) Compare the result of computing (-20)/16 following the rules you learned in elementary school with the result you get with the above code. (0.2 points)

    (-20)/16 by hand is -(20/16) = -1

    (-20)/16 by shifting is (-20)>>4 = -101002>>4 = 1111011002>>4 = 111102>>4 = -2

    b) Explain the difference. (Hint, it has to do with the remainder after division.)

    Doing it by hand, we conventionally truncate the result toward zero, converting -1.25 to -1. In this case, the remainder after division is -4.

    Shifting truncates toward the next lower value, converting -1.25 to -2. In this case, the remainder after division is +12.

    (0.3 points)

  3. Background: Consider this little subroutine, packaged as a file called sub.a that is designed to be assembled separately from its caller:
            TITLE   "sub.a, a subroutine"
            INT     SUB
    SUB:    ; returns R3 = sum i from i=min to max (constant bounds)
            ; uses    R4 = i
            LIS     R4,MIN          ; i = min
            LIS     R3,0            ; sum = 0
    LOOP:
            CMPI    R4,MAX
            BGT     QUIT            ; while (i <= max) {
    ;       ----- cut here -----
            ADD     R3,R3,R4        ;   sum = sum + i
            BR      LOOP
    QUIT:                           ; }
            JUMPS   R1
    MIN     =       5
    MAX     =       10
    

    A problem: Divide this subroutine into two separately assembled files, one containing all the code above the line saying "cut here" and one containing all the code below that line. The first half should continue to be stored in the file sub.a while the second half goes in a new file, sub2.a. Your goal is to make the bare minimum changes necessitated by this division, while retaining as much as possible of the original logic and structure of the program. That is, MIN and MAX should still be defined in the same place, which is now in sub2, and the return from the subroutine is now from near the end of sub2.a even though the entry point to the subroutine is in a different file, sub.a. (1.0 points)

    Note: This is not a recommended programming style! This problem is really about understanding the limitations that apply to the use of external symbols. There are places where they do not work, and as a consequence, you have to substitute less efficient and possibly less readable code for several of the simple instructions above.

    Your answer should be in the form of blocks of code, one representing each file, where the code in each file has a TITLE directive naming that file. Obviously, you will have to add INT LOOP and EXT QUIT to sub.a, and you will have to add EXT LOOP and INT QUIT to sub2.a, but there is more work to do because of the machine instructions that do not work with external symbols.

    Comments in the following code indicate and explain changes

            TITLE   "sub.a, the first half of a subroutine"
            INT     SUB
    
            INT     LOOP            ; -- added
            EXT     MIN             ; -- added
            EXT     MAX             ; -- added
            EXT     QUIT            ; -- added
            EXT     CONTINUE        ; -- added
    
    SUB:    ; returns R3 = sum i from i=min to max (constant bounds)
            ; uses    R4 = i
            LIS     R4,MIN          ; i = min
            LIS     R3,0            ; sum = 0
    LOOP:
            LIS     R5,MAX          ; -- added: CMP R4,MAX is illegal
            CMPI    R4,R5           ; -- changed
            BGT     QUITX           ; while (i <= max) { -- changed: can't BR QUIT
            LIL     R5,CONTINUE     ;   -- added
            JUMPS   R5              ;   -- added -- can't fall through to part b
    
    QUITX:  LIL     R5,QUIT         ; -- added
            JUMPS   R5              ; -- added
    ;       ----- cut here -----
    
            TITLE   "sub2.a, second half of subroutine
    ;       ----- cut here -----
            INT     CONTINUE        ; -- added
            INT     QUIT            ; -- added
            EXT     SUB             ; -- added
            EXT     LOOP            ; -- added
    
    CONTINUE:                       ;   -- added -- can't fall through to here
            ADD     R3,R3,R4        ;   sum = sum + i
            LIL     R5,LOOP         ;   -- added
            JUMPS   R5              ;   -- changed -- can't BR LOOP
    QUIT:                           ; }
            JUMPS   R1
    MIN     =       5
    MAX     =       10
    

    A number of students tried using a COMMON block to share access to MIN and MAX between the two parts of the program. As far as we could tell, none of them use it correctly.

  4. Background: Consider the following description of a stream class.
    ; stream.h -- standard interface to all streams
    
    ; all stream objects have the following core structure
    STRCLASS=       0       ; pointer to stream class descriptor
    ;                       ; each distinct subclass may add fields here
    ;                       ; subclasses must provide the object size
    
    ; each subclass must provide a class descriptor that conforms
    ; to the following structure:
    PUT     =       0       ; pointer to the put method
            ; expects R3 = pointer to stream object
            ;         R4 = character to put
    
    GET     =       4       ; pointer to the get method
            ; expects R3 = pointer to stream object
            ; returns R3 = one character from the stream
    
    CLOSE   =       8       ; pointer to the close method
            ; expects R3 = pointer to stream object
    

    A Problem Assume that the global variable STDOUT (an external symbol) points to a stream object, write code to put the character "a" out to that stream. (1.0 points)

    Here is a pedantic solution, avoiding optimization:

            LIL     R3,STDOUT
            LOADS   R3,R3           ; -- parameter R3, the value of STDOUT
            LIS     R4,'a'          ; -- parameter R4, 'a'
            ADDI    R2,R2,ARSIZE
            LOAD    R1,R3,STRCLASS  ; -- get pointer to class descriptor
            LOAD    R1,R1,PUT       ; -- get pointer to method from descriptor
            JSRS    R1,R1           ; stdout.put('a')
            ADDI    R2,R2,-ARSIZE
    

    Here is a solution that replaces LOAD rd,rx,0 with LOADS rd,rx to make it faster:

            LIL     R3,STDOUT
            LOADS   R3,R3           ; -- parameter R3, the value of STDOUT
            LIS     R4,'a'          ; -- parameter R4, 'a'
            ADDI    R2,R2,ARSIZE
            LOADS   R1,R3           ; -- get pointer to class descriptor
            LOADS   R1,R1           ; -- get pointer to method from descriptor
            JSRS    R1,R1           ; stdout.put('a')
            ADDI    R2,R2,-ARSIZE