Assignment 4, due Feb 14

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. Background: Consider this fragment of SMAL assembly code from Chapter 4 of the notes:
     00001000: D4  12                3          LIS     R4, #12
     00001002: E5  654321            4          LIL     R5, #654321
     00001006: 32  45                5          ADD     R2, R4, R5
    

    A problem: This data fills memory locations 100016 to 100716, a total of 4 halfwords, but the assembler listing shows it as a sequence of 8-bit bytes and one 24-bit triple-byte. Show the data as a sequence of hexadecimal address-value pairs, where each value is a halfword. (0.8 points)

    The easy way to solve this problem is to start by converting it to a sequence of bytes:

    00001000: D4  -- from line 3
    00001001: 12
    00001002: E5  -- from line 4
    00001003: 21  --   low byte of 24-bit value
    00001004: 43  --   middle byte of 24-bit value
    00001005: 65  --   high byte of 24-bit value
    00001006: 32  -- from line 5
    00001007: 45
    

    Then, bunch the bytes into pairs.

    00001000: 12D4
    00001002: 21E5
    00001004: 6543
    00001006: 4532
    

    Note that you need to use the fact that this machine is a lowbyter twice here, once in undoing the 24-bit value into a sequence of bytes, and once in reassembling these bytes into halfwords.

  2. Background: Here is SMAL code to assemble a sequence of bytes into memory:
            USE     "hawk.h"
            ALIGN   2       ; we begin at an even address
            B       #D3
            B       #01
            B       #13
            B       #C2
            B       #F4
            B       #F3
    

    a) Disassemble this code -- that is, convert it from a sequence of B assembly directives to an equivalent sequence of SMAL Hawk machine instructions (things like ORIS R1,7 or LIL R5,7000, although neither of these is part of the answer). Assembling your sequence should load exactly the same result into memory. (0.6 points)

    First, pair up the bytes and convert them to binary, since the Hawk manual is all in binary, not Hex.

            USE     "hawk.h"
            ALIGN   2       ; we begin at an even address
            B       2#11010011 2#00000001
            B       2#00010011 2#11000010
            B       2#11110100 2#11110011
    

    Now, look them up in the Hawk manual, appendix B.1:

            USE     "hawk.h"
            ALIGN   2       ; we begin at an even address
            LIS     R3,1
            ADDSI   R3,2
            MOVE    R4,R3
    

    b) If you execute the above sequence of machine instructions, starting with the program counter pointing to the first byte and stopping after the last byte, what registers will have been changed, and to what values? (0.6 points)

    R3 = 3 (that is, the constant 1 incremented by 2)
    R3 = 3 (that is, a copy of R3)

    Hint: You can solve this by reading and hunting through Chapter 4, or you can solve this by using the SMAL assembler to assemble the code and then loading it into the Hawk emulator and letting the emulator disassemble it and run it. You will learn the most if you do both, using one approach to check your work done using the other.

    The solutions above were done by hand. Here is the result of assembling the hand-made code from part a):
                                     1          USE     "hawk.h"
                                     2          ALIGN   2       ; we begin ...
    +00000000: D3  01                3          LIS     R3,1
    +00000002: 13  C2                4          ADDSI   R3,2
    +00000004: F4  F3                5          MOVE    R4,R3
    

    In the above, note that the sequence of bytes given in the assembly listing is identical to the sequence of bytes given in the problem statement!

    Running the Hawk emulator with the object file obtained from assembling either the original byte sequence or the result of the hand translation exercise in part a, you get the following display showing the disassembled code. This screen capture was made after pressing the "s" key 3 times, making it single-step through three instructions so you can also see the values loaded in registers 3 and 4:

     HAWK EMULATOR
       /------------------CPU------------------\   /----MEMORY----\
       PC:  00000006                R8: 00000000  *000000: LIS     R3,#01
       PSW: 00000000  R1: 00000000  R9: 00000000   000002: ADDSI   R3,#2
       NZVC: 0 0 0 0  R2: 00000000  RA: 00000000   000004: MOVE    R4,R3
                      R3: 00000003  RB: 00000000 ->000006: NOP
                      R4: 00000003  RC: 00000000   000008: NOP
                      R5: 00000000  RD: 00000000   00000A: NOP
                      R6: 00000000  RE: 00000000   00000C: NOP
                      R7: 00000000  RF: 00000000   00000E: NOP
    

  3. Background: Here is a SMAL Hawk macro to load an arbitrary constant. It makes an intelligent choice between LIS, LIL or a longer 2 instruction sequence depending on the value of the constant:
            MACRO   LI =dst, =const
              IF (const >= -#80) & (const <= #7F)
                LIS dst, const
              ELSEIF (const >= -#800000) & (c < #7FFFFF)
                LIL dst, const
              ELSE
                LIL  dst, const >> 8
                ORIS dst, const & #FF
              ENDIF
            ENDMAC
    

    With this macro, a programmer could write LI R3, (A + B) and let the assembler decide which instruction or instruction sequence to use, depending on the value of the sum.

    Note: The IF, ELSEIF, ELSE and ENDIF operations are fairly obvious. They control which part of the body of the macro gets assembled and which parts are skipped, depending on the values of the macro parameters. If that is insufficient, you are welcome to look at Chapter 5 of the SMAL32 manual for additional discussion.

    Aside: So why isn't the LI macro in the hawk.h file? Because it, along with many similar macros, would raise the level of the language closer to a high level language, so you would learn less about machine architecture as you learned to program in what would end up being just a very clumsy middle-level programming language.

    A problem: Write a similar macro called AI standing for add immediate. This macro would select between doing nothing (if the immediate constant was zero), using ADDSI, using ADDI or loading the constant into a register (user R1) and then using a plain ADD. Note that you may need to subdivide the "loading a constant" alternative depending on the value of the constant. Feel free to crib code for this purpose from the LI macro given above. (1 point)

    Clarification: In response to a student question, the user might write AI R3,VALUE, and depending on the value of the second operand, the macro would expand to either ADDSI R3,VALUE or ADDI R3,R3,VALUE or something else.

    This was a difficult problem, only a few students got it anywhere near right, and only a few students thought to ask questions about it. Here is a good answer:

            MACRO   AI =dst, =const
              IF (const = 0)
                ; no work to do?
              IF (const >= -#8) & (const <= #8)
                ADDSI dst, const
              ELSEIF (const >= -#8000) & (c < #7FFF)
                ADDI dst, dst, const
              ELSE
                IF (const >= -#800000) & (c < #7FFFFF)
                  LIL  R1, const
                ELSE
                  LIL  R1, const >> 8
                  ORIS R1, const & #FF
                ENDIF
                ADD  DST, DST, R1
              ENDIF
            ENDMAC
    

    Among the issues that complicate the problem: The ADDSI instruction cannot add zero, because it has provisions to handle +8 as well as -8; this requires a special case for adding zero.

    The above solution uses nested if statements just to show that they are possible. It is probably easier to understand this solution that just uses another ELSEIF at the end.

            MACRO   AI =dst, =const
              IF (const = 0)
                ; no work to do?
              IF (const >= -#8) & (const <= #8)
                ADDSI dst, const
              ELSEIF (const >= -#8000) & (c < #7FFF)
                ADDI dst, dst, const
              ELSEIF (const >= -#800000) & (c < #7FFFFF)
                LIL  R1, const
                ADD  DST, DST, R1
              ELSE
                LIL  R1, const >> 8
                ORIS R1, const & #FF
                ADD  DST, DST, R1
              ENDIF
            ENDMAC