• No results found

6.3 Parameter Passing

Subroutines often require data from the program to complete their function. For example, a subroutine that converts a hex value to the equivalent ASCII character code

Instructions in main program Instructions in delay subroutine DELAY 1 3 5 6 4 2 JSR DELAY JSR DELAY RTS JSR DELAY

Figure 6.6 Example of a Subroutine

1. How would you describe a subroutine in your own words? 2. What value does a subroutine provide to a program? 3. How is a subroutine called?

4. How many bytes are pushed onto the stack when a subroutine is called? What are they?

5. What must happen to achieve balanced use of the stack?

145

must be provided the hex value that will be converted. In the same manner, subroutines often have the need to return data to the calling program. When the conversion is completed by the hex-to-ASCII conversion subroutine, the ASCII character code must be returned to the calling program. Parameter passing is the name given the process of passing data to and from subroutines.

There are two primary methods of passing these parameters to and from subroutines, pass by value and pass by reference. The pass by value method sends a copy of data to the subroutine. The subroutine uses this copy of the data in whatever manner necessary to complete the function of the subroutine. The pass by reference method sends an address of the data to the subroutine. The address represents the location in memory where the data is stored. During the execution of the subroutine, the data is accessed via this address.

The easiest way to pass by value is to load a processor register with the data prior to calling the subroutine. The subroutine uses the data from the register during the execution of the subroutine. The pass-by-reference method loads either the X or Y register with an address where the data is stored. The subroutine then must use an indexed mode instruc- tion to access the data. Data can also be returned to the calling program by using either of these methods. It is common to pass a value to a subroutine via a processor register to have the value processed and then to return the processed value in the same register.

Example 6.4

Problem: Write a subroutine to accomplish a squaring function. Use the following flowchart as an outline of what the subroutine should do. Use the pass-by-value technique to pass the data to and from the subroutine. Use AccA to pass the data to the subroutine and return the squared data in AccD. Assemble the code starting with location $0180.

Solution: The squaring function can be accomplished in two instructions. Since the value to be squared is in AccA, this value needs to be copied to AccB to prepare for the multiplication. The square is found by multiplying the contents of AccA by the contents of AccB. The result of the MUL instruction is automatically stored in AccD.

Example 6.4

Load AccA with value to be squared Square the value END Squaring Subroutine

Copy the value in order to multiply

Multiply

Return

Example 6.4 Flowchart

146

0001 0180 16 SQUARE TAB ;duplicate value (A) → B

0002 0181 3d MUL ;square value, (A) x (B) → D

0003 0182 39 RTS ;return to calling program

In some cases, subroutines do not require any data from the calling program. They perform operations that are independent of the data being processed. A time delay is an example of this type of subroutine. The time delay executes a set of instructions a fixed number of times and then returns to the calling program. The job of the time delay is simply to keep the processor busy for a fixed length of time.

Balanced Use of Stack

Often during execution of a subroutine, the contents of the registers that are changed by the routine are first pushed onto the stack. This way the original contents of these processor registers can be restored at the end of the routine by pulling them back off the stack. For example, if the X register is used temporarily by a subroutine, as shown in Figure 6.7, it is wise to push the contents of the X register onto the stack at the beginning of the subroutine. The routine can then use the X register for any purpose, because the original contents are saved on the stack. At the end of the subroutine, the contents of the X register must be restored by executing a pull instruction. This is called balanced use of the stack. Balanced use implies that whatever is pushed onto the stack is removed from the stack before another process is done.

NOTE: Values must pulled from the stack in an order opposite to that in which they were pushed onto the stack to maintain the integrity of the original data. For example, PSHA, PSHX must be complemented with PULX, PULA.

When a subroutine is called, the two-byte return address is pushed onto the stack by the JSR or BSR instruction, and the RTS pulls these two bytes back off. This is another example of balanced use of the stack.

*Delay Subroutine

DELAY PSHX ;Save X (2-bytes) to stack

LDX #$0D06 ;Use X as counter

AGAIN DEX ;Loop until X = 0

BNE AGAIN

PULX ;Restore X (2-bytes) from stack

RTS

Figure 6.7 Balanced Use of Stack

147

Self-Test Questions 6.3