Homework 5 Solutions

22C:18, Summer 1997

Douglas W. Jones
  1. Given that PROC is an external procedure, why is
    	JSR	R1,PROC
    
    illegal while the following is legal:
    	LIS	R1,0
    	JSR	R1,R1,PROC
    
    JSR R1,PROC is illegal when PROC is an external symbol because it uses PC relative addressing and our linker is not smart enough to figure out how to patch up PC-relative addresses of external symbols.

    LIS R1,0/JSR R1,R1,PROC is legal because here, PROC is a 16 bit constant added to R1 (which is set to 0). Our linker can handle filling in the value of a 16 bit constant with a value defined elsewhere.

  2.         Code                 Memory Words    Memory Cycles
            ==================   ============    =============
    
            LIS     R1,0         0.5             0.5
            JSR     R1,R1,PROC   1.0             1.0
                                -----           -----
                                 1.5    total    1.5
    
            LOAD    R1,PPROC     1.0             1.0 + 1.0
            JSRS    R1,R1        0.5             0.5
                                -----           -----
                                 1.5    total    2.5
    
    The above analysis suggests that the two sequences have the same memory requirements and that the top sequence (the new one) is faster! However, because it only uses a 16 bit address to point to PROC, it is impossible to use it if PROC is outside the first 64K of memory. In contrast, the second calling sequence lets the linker fill in the entire 32 bit address of PROC in the word PPROC, which is locally addressed using PC relative addressing.

  3. To write an improved version of the PROCBEGIN that is illegal inside a procedure or inside the body of the main program, note that qARq is set to -1 outside of a procedure or function, and it is set to zero or positive values inside. So, we can check the value of qARa to detect misuse of this macro. The same trick could be used with MAINBEGIN.
            MACRO   PROCBEGIN name
              IF qARq < 0
                INT     name
                name:
                STORES  R1,R2
                qARq =  4
              ELSE
                ERROR   PROCBEGIN used illegally
              ENDIF
            ENDMAC
    
    
  4. Extending the above to create a universal end macro is straightforward, except that there is no universal way to detect the difference between procedures and main programs (each may have local variables, so qARq may be positive in both). Also, note that the END pseudoop already claims the name END, so we've got to use a new name. To solve the first problem, we have to invent a way to distinguish between main programs and procedures; we'll add a new symbol, qMAINq, that is true in main programs and false elsewhere. To solve the second problem, we'll invent a stupid new name:
            MACRO   MAINBEGIN name
              IF qARq < 0
                S       name
                name:
                LOAD    R2,pStacKp
                LIS     R1,0
                JSR     R1,R1,DSPINI
                qARq =  0
                qMAINq= -1
              ELSE
                ERROR   MAINBEGIN used illegally
    	  ENDIF
            ENDMAC
    
            MACRO   ALLEND
    	  IF qARq < 0
    	    ERROR   END used illegally
              ELSEIF qMAINq
                LIS     R1,0
                JUMPS   R1
                qARq =  -1
                qMAINq= 0
              ELSE
                LOADS   R1,R2
                JUMPS   R1
                qARq =  -1
              ENDIF
            ENDMAC
    
            qMAINq= 0
    

  5. Here's a rewrite of Homework 4, problem 1, using these macros:
    	   TITLE   funct.a, homework 5 problem 5 
    	   USE     "/group/class/22c018/hawk.macs"
    	   USE     "/group/class/22c018/highlevel.h"
    
       ; -------------------
    	   PROCBEGIN FUNCT
    	   LOCAL     X
    	   LOCAL     A
    	   ; on entry, R3 = parameter X
    	   ; on exit, R3 = result
    	   ; uses R3
    	   CMPI    R3,2       ; see if X <= 2
    	   BLE     FUNQT      ;   quit and return X if so
    
    	   PUT     R3,X       ; save X
    
    	   ADDSI   R3,-1      ; set up parameter for call
    	   CALL    FUNCT
               PUT     R3,A       ; save result as A
               GET     R3,X       ; recorver X for next call
               CALL    FUNCT      ; recursive call FUNCT(X-3)
               GET     R1,A       ; recover A from first call
               ADD     R3,R3,R1   ; setup to return A+FUNCT(X-3)
    
       FUNQT:
               ALLEND             ; return!
       ; -------------------
    
               EXTERNAL DSPDEC
    
    	   MAINBEGIN
               LIS     R8,1       ; initialize loop counter I
       LP:
               MOVE    R3,R8      ; setup parameter for call
               CALL    FUNCT      ; call FUNCT(I)
               LOADI   R4,8       ; setup parameter for call
               CALL    DSPDEC     ; call DSPDEC(FUNCT(I),8)
               ADDSI   R8,1       ; increment I
               CMPI    R8,8       ; test for end of loop
               BLT     LP         ;   continue loop if I < 8
    	   ALLEND             ; done!
    
               END