Page 302 - Introduction to Microcontrollers Architecture, Programming, and Interfacing of The Motorola 68HC12
P. 302

9,5 Procedure Calls and Arguments                                    279


        9.5 Procedure Calls and Arguments

        A C procedure is generally called using a JSR orBSR instruction, with the input
        arguments pushed on the stack. The return value of a function is generally left in
        accumulator D. If the input argument is a vector, or an "&" sign appears before the
        name, then the address is passed on the stack, using call-by-name; otherwise the data
        itself is pushed on the stack, using call-by-value. However, the rightmost argument is
        passed into a function through a register. The function might push this register value
        inside it, as a local variable. Passing one argument this way improves efficiency, because
        even if it is pushed on the stack inside the function itself, its code therein appears just
        once in a program, rather than each time the subroutine is called. As an example, the
        procedure power can be called by main( ) in Figure 9.14a. Figure 9.14b shows the
        calling procedure's assembly language.
            Figure 9.15 shows the stack within the procedure that was called; its assembly
        language is shown Figure 9.14c. The while loop requires the test at the end of the loop
        and a branch at the beginning of the while loop to that test program sequence. Observe
        from Figure 9.14c that call-by-value argument j is generally in accumulator A. The test
        requires checking the argument j before it is decremented, so the instruction PS HA
        saves j, the DEC instruction decrements j, and the BNE instruction tests the value
        obtained by the LDAB 1, SP+ instruction.
            The EMUL instruction multiplies the value in D by the value in Y. We passed the
        address of argument i to power, merely to show how call-by-name can be handled. It
        was pushed on the stack. Note from Figure 9.15 that this address is at 2 , SP. The int
        value at that location can be read into index register Y by LDY 2, SP LDD 0, Y and
        the other multiplier, a local variable, is read into Y by the TFR X, Y. The data are
        multiplied and the result stored in the local variable using TFR D, X. Note that the final
        returned value is passed in accumulator D.
            It is also possible to pull the return address and deallocate the procedure's arguments
        at the end of the procedure before returning to the main program. This is similar to the
        passing of the rightmost argument in a register. In some sense these optimization
        techniques are just minor modifications. However, they can improve static efficiency. If a
        procedure is called from ten different places in the main program, then putting push and
        pull instructions within the called procedure removes these instructions from ten places
        in the calling sequence and puts only one copy in the called procedure. Moreover, the
        technique of putting the first input argument in accumulator D works especially well for
        small procedures with only one argument; we may not need to save the argument on the
        stack at all, merely use the value in accumulator D. However, the last technique of
        pulling the program counter and balancing the stack inside the called procedure has a
        significant limitation. It is not possible to have a procedure with an arbitrary number of
        arguments when the called procedure removes the same number of bytes from the stack
        whenever it is called. The C printf procedure allows an arbitrary number of arguments,
        so it would not be able to pull the program counter and balancing the stack inside it.
   297   298   299   300   301   302   303   304   305   306   307