Assignment 6, Solutions

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

  1. Background: One approximation for π is 333/106. In a high level language, you could write a function to (approximately) multiply an integer by π as follows:
    unsigned int timespi( unsigned int i ) {
        return (i * 333)/106;
    }
    

    The Hawk monitor provides tools for multiplication and division. The definitive documentation for the monitor is in the monitor.h file which you can download or inspect at
    -- http://homepage.cs.uiowa.edu/~dwjones/arch/hawk/monitor_h.txt

    A Problem: Write a SMAL Hawk subroutine equivalent to the timespi routine given above. It should take its argument in R3 and return its result in R3, while conforming to the Hawk calling conventions. (1.0 points)

    ; times pi subroutine (multiply R3 by 333/106)
    ; activation record
    ;RETAD  =       0       ; the return address
    ARSIZE  =       4       ; the return address
    
    TIMESPI:        ; expects R3 = i, the unsigned integer argument
                    ; returns R3 = i times pi
                    ; wipes out R4 - R6
            STORES  R1,R2
            MOVE    R4,R3           ; -- parameter i
            LIL     R5,333          ; -- parameter 333
            ADDI    R2,R2,ARSIZE
            LIL     R1,TIMESU
            JSRS    R1,R1           ; i = timesu( i, 333 )
            ADDI    R2,R2,-ARSIZE   ; -- *
                                    ; -- parameter i is already in place
            LIS     R5,106          ; -- parameter 106
            ADDI    R2,R2,ARSIZE    ; -- *
            LIL     R1,DIVIDEU
            JSRS    R1,R1           ; i = divideu( i, 106 )
            ADDI    R2,R2,-ARSIZE
            LOADS   R1,R2
            JUMPS   R1              ; return i
    

    Note, finding out what registers this routine actually used required looking up each of the subroutines it calls to find out what registers they used.

    Also note that this code can be optimized by deleting the two lines marked with -- * comments.

  2. Background: To convert from text to binary, each digit must be converted and then they must be combined. This is easy with the decimal digits in ASCII:
            char digit = ... (whatever)
            int value = digit - "0";
    

    This only works because the ASCII representations of the digits are in the right numerical order. The situation is harder when this is not true. Consider the system of hexadecimal digits that was used on the Illiac I computer:

            0 1 2 3 4 5 6 7 8 9 K S N J F L
    

    a) Give SMAL Hawk code to define a constant array of integers indexed by the character code, with all of the array elements set to 16 except for the elements corresponding to Illiac I hexadecimal digits -- each of these should have its corresponding integer value, so, for example, A['7'] should hold seven. (1.0 points)

    Suggestion: The answer can be an aligned array initialized by W directives. If you write 16 values per line, the solution would be only 8 W directives.

            ALIGN   4
    A:      W       16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16 ; control
            W       16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16 ; control
            W       16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16 ; ' ' to '/'
            W        0, 1, 2, 3,  4, 5, 6, 7,  8, 9,16,16, 16,16,16,16 ; '0' to '?'
            W       16,16,16,16, 16,16,14,16, 16,16,13,10, 15,16,12,16 ; '@' to 'O'
            W       16,16,16,11, 16,16,16,16, 16,16,16,16, 16,16,16,16 ; 'P' to '_'
            W       16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16 ; '`' to 'o'
            W       16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16 ; 'p' to del
    

    If you wanted to allow lower case letters to be acceptable substitutes for their upper case equivalents, you'd change the last two lines to:

            W       16,16,16,16, 16,16,14,16, 16,16,13,10, 15,16,12,16 ; '`' to 'o'
            W       16,16,16,11, 16,16,16,16, 16,16,16,16, 16,16,16,16 ; 'p' to del
    

    Note, in preparing the above table, it was useful to have the ASCII table in hand. The tables from Chapter 2 of the notes or the table output by the man ascii are equivalent for this purpose.

    b) Write a subroutine, based on the array you defined in part a), that takes a character passed in R3 and returns the corresponding value from the array in R3, conforming to the Hawk calling conventions. (1.0 points)

    GETASUBCH:      ; given   R3 = ch
                    ; returns R3 = A[ch]
                    ; uses    R4
            LEA     R4,A    ; R4 points to A (which must be a local constant)
            ADDSL   R3,R4,2 ; R3 points to A[ch]
            LOADS   R3,R3   ; R3 holds the value of A[ch]
    	JUMPS   R1      ; return
    

    The above is the best solution, but the same computation can be done other ways. Here is an alternative body for the above subroutine:

            LIL     R4,A    ; R4 points to A (which could be global)
            SL      R3,2    ; R3 times 4 because components of A are 4 bytes each
            ADD     R3,R3,R4; R3 points to A[ch]
            LOAD    R3,R3,0 ; R3 holds the value of A[ch]
    

    Just because we can, here is another alternative subroutine body:

            LEA     R4,A    ; R4 points to A (which must be a local constant)
            ADD     R3,R3,R3; double R3
            ADD     R3,R3,R3; double again
            ADD     R3,R3,R4; R3 points to A[ch]
            LOADS   R3,R3   ; R3 holds the value of A[ch]