CS 273: Passing Parameters

Introduction

For the second example of calling procedures on the HC11, we'll create another pretty useless function: this one will do eight-bit addition. If we were writing a function prototype for this function in a high level language, it would look like this:


char add8(char op1, char op2);

So the function takes two parameters, both eight bit integers (i.e. chars. It returns another eight bit integer. We're going to use pretty standard parameter and return value passing techniques here: we'll pass parameters on the stack, and return the function value in the A accumulator.

One thing to mention is that this program shows how to pass parameters, but is till incomplete in a couple of ways. First, it doesn't have any local variables, and second, it corrupts the IX index register. We'll be cleaning these problems up in later examples.

We'll start by just writing the main program, and assuming that the function does the right thing. Then we'll write the function to go along with it.

Main Program

In a high level language, our main program will look like this:


res = add8(12, 34);

so it will add 12 to 34, and put the result in a global variable named res (we're using a global because we haven't talked about how to put local variables on the stack yet).

In assembly, our main program will initialize the stack pointer, push the parameters, and call the function. Then it'll clean the parameters off the stack, and put the result in a variable. Here's how it looks:


        org  EEPROM
start   lds  #STACK  * initialize stack pointer

        ldaa #34     * push parameters right-to-left (so the first
        psha         * parameter is closest to top of stack)

        ldaa #12
        psha

        jsr  add8    * call function

        ins          * clean up parameters (two bytes pushed, so 
        ins          * need to increment SP twice)

        staa res     * store return value in global variable.

eloop   bra  eloop

Function add8()

Now for our function. We need to get the parameters off the stack, add them together, and leave the result in A. The way we get data out of the activation record is by using indexed addressing — unfortunately, we can't use indexed addressing from the stack pointer directly, so we need to use an index register for it. We'll use IX, since the code will be smaller than IY. Here's our code:


add8    tsx          * IX = SP+1

        ldaa 2,x     * A = param1+param2
        adda 3,x
        rts

Running the Example

Here's a link to the complete example program. Let's watch what happens as it runs.

  1. We'll start by initializing the stack pointer. After this instruction, SP will contain $00ff.
    
    0009 f800 8e 00 ff                start   lds  #STACK  * initialize stack pointer
    0010                              
    
    
  2. Now we'll push the parameters. After these four instructions, $0c and $22 will be the top two elements on the stack (and SP will be $00fd).
    
    0011 f803 86 22                           ldaa #34     * push parameters right-to-left (so the first
    0012 f805 36                              psha         * parameter is closest to top of stack)
    0013                              
    0014 f806 86 0c                           ldaa #12
    0015 f808 36                              psha
    0016                              
    
    
  3. Call the function. We'll go to address $f812, and push $f80c (the return address) on the stack. So the stack will contain $f8 $0c $0c $22.
    0017 f809 bd f8 12                        jsr  add8    * call function
    
    
  4. Now we're in the function. We need to set up our activation record pointer. Since the top element of the stack is at $00fc, that's what IX will contain.
    
    0026 f812 30                      add8    tsx          * IX = SP+1
    
    
  5. Some actual work gets done! We add the two parameters together. They are at offsets 2 and 3 from IX, because the return address was pushed on top of them.
    
    0028 f813 a6 02                           ldaa 2,x     * A = param1+param2
    0029 f815 ab 03                           adda 3,x
    
  6. Our function value is now in A, so we can just return to the main program. Remember that this pops the return address off the stack — we can actually still see it in memory, but the stack pointer has moved up above it.
    
    0030 f817 39                              rts
    
  7. Now we're back in the main program (at address $f80c), but our parameters are still sitting on the stack. We need to get rid of them. The ins instruction just adds one to the stack pointer.
    
    0019 f80c 31                              ins          * clean up parameters (two bytes pushed, so 
    0020 f80d 31                              ins          * need to increment SP twice)
    
  8. Remember we were supposed to save our function return in a variable. That happens now.
    
    0022 f80e 97 0a                           staa res     * store return value in global variable.
    

And we're done! The program just goes into its infinite loop now.


Last modified: Mon Feb 25 11:32:07 MST 2008

Valid HTML 4.01 Transitional