• Keine Ergebnisse gefunden

PARAMETER PASSING TECHNIQUES

Im Dokument Assembly Language Subroutines (Seite 59-64)

The most common ways to pass parameters on the Z80 microprocessor are 1. In registers. Seven 8-bit primary user registers (A, B, C, D, E, H, and L) are available, and the three register pairs (BC, DE, and HL) and two index registers (IX

CHAPTER 1 GENERAL PROGRAMMING METHODS

47

and IY) may be used readily to pass addresses. This approach is adequate in simple cases, but it lacks generality and can handle only a limited number of parameters. The programmer must remember the normal uses of the registers in assigning parameters.

In other words,

· The accumulator is the obvious place to put a single 8-bit parameter.

· Register pair HL is the obvious place to put a single address-length (16-bit) parameter.

· Register pair DE is a better place to put a second address-length parameter than register pair Be, because of the EX DE,HL instruction.

· An index register (IX or IY) is the obvious place to put the base address of a data structure when elements are available at fixed offsets.

This approach is reentrant as long as the interrupt service routines save and restore all the registers.

2. In an assigned area of memory. There are two ways to implement this approach.

One is to place the base address of the assigned area in an index register. Then particular parameters may be accessed with fixed offsets. The problem here is that the Z80's indexing is extremely time-consuming. An alternative is to place the base address in HL. Then parameters must be retrieved in consecutive order, one byte at a time.

In either alternative, the calling routine must store the parameters in memory and load the starting address into the index register or HL before transferring control to the subroutine. This approach is general and can handle any number of parameters, but it requires a lot of management. If different areas of memory are assigned for each call or each routine, a unique stack is essentially created. If a common area of memory is used, reentrancy is lost. In this method, the programmer is responsible for assigning areas of memory, avoiding interference between routines, and saving and restoring the pointers required to resume routines after subroutine calls or interrupts.

3. In program memory immediately following the subroutine call. If this approach is used, remember the following:

. The base address of the memory area is at the top of the stack; that is, the base address is the normal return address, the location of the instruction immediately following the call. The base address can be moved to an index register by popping the stack with

POP Xy :RETRIEVE BASE ADDRESS OF PARAMETERS N ow access the parameters with fixed offsets from the index register. For example, the accumulator can be loaded with the first parameter by using the instruction

LD A, (Xy+O) :MOVE FIRST PARAMETER TO A

48

Z80 ASSEMBLY LANGUAGE SUBROUTINES

. All parameters must be fixed for a given call, since the program memory is typically read-only .

. The subroutine must calculate the actual return address (the address immediately following the parameter area) and place it on top of the stack before executing a RET instruction.

Example

Assume that subroutine SUBR requires an 8-bit parameter and a 16-bit parameter.

Show a main program that calls SUBR and contains the required parameters. Also show the initial part of the subroutine that retrieves the parameters, storing the 8-bit item in the accumulator and the 16-bit item in register pair HL, and places the correct return address at the top of the stack.

Subroutine call

Subroutine SUBR:

CALL SUBR ;EXECUTE SUBROUTINE DEFB PAR8 ;8-BIT PARAMETER

;UPDATE RETURN ADDRESS

remainder of subroutine • • •

;RETURN TO NEXT INSTRUCTION

The initial POP xy instruction loads the index register with the return address that CALL SUBR saved at the top of the stack. In fact, the return address does not contain an instruction; instead, it contains the first parameter (PAR8). The next instructions move the parameters to their respective registers. Finally, adding 3 to the return address and saving the sum in the stack makes the final RET instruction transfer control back to the instruction following the parameters.

This approach allows parameter lists of any length. However, obtaining the parame-ters from memory and adjusting the return address is awkward at best; it becomes a longer and slower process as the number of parameters increases.

CHAPTER 1 GENERAL PROGRAMMING METHODS

49

4. In the stack. When using this approach, remember the following:

· CALL stores the return address at the top of the stack. The parameters that the calling routine placed in the stack begin at address ssss

+

2, where ssss is the contents of the stack pointer. The l6-bit return address occupies the top two locations of the stack, and the stack pointer itself always refers to the lowest occupied address, not the highest empty one.

· The subroutine can determine the value of the stack pointer (the location of the parameters) by (a) storing it in memory with LD (ADDR),SP or (b) using the sequence

LD HL,O ADD HL,SP

~MOVE STACK POINTER TO HL

This sequence places the stack pointer in register pair HL (the opposite of LD SP,HL).

We can use an index register instead of HL if HL is reserved for other purposes.

· The calling program must place the parameters in the stack and assign space for the results before calling the subroutine. It must also remove the parameters from the stack (often referred to as cleaning the stack) afterward. Cleaning the stack is simple if the programmer always places the parameters above the empty area assigned to the results. Then the parameters can be removed, leaving the results at the top. The next example illustrates how this is done. An obvious alternative is for the results to replace some or all of the parameters.

Stack locations can be allocated dynamically for results with the sequence LD HL,-NRESLT

ADD HL,SP LD SP,HL

~LEAVE ROOM FOR RESLILTS

This sequence leaves NRESLT empty locations at the top of the stack as shown in Figure 1-8. Of course, if NRESLT is small, simply executing DEC SP NRESLT times will be faster and shorter. The same approaches can be used to provide stack locations for temporary storage.

Example

Assume that subroutine SUBR requires an 8-bit parameter and a l6-bit parameter, and that it produces two 8-bit results. Show a call of SUBR, the placing of the parameters in the accumulator and register pair HL, and the cleaning of the stack after the return. Figure 1-9 shows the appearance of the stack initially, after the subroutine call, and at the end. Using the stack for parameters and results will generally keep the parameters at the top of the stack in the proper order. In this case, there is no need to save the parameters or assign space in the stack for the results (they will replace some or all of the original parameters). However, space must be assigned on the stack for temporary storage to maintain generality and reentrancy.

50

Z80 ASSEMBLY LANGUAGE SUBROUTINES

HL,(PAR16);OBTAIN 16-BIT PARAMETER

HL ;MOVE 16-BIT PARAMETER TO STACK A, (PAR8) ;OBTAIN 8-BIT PARAMETER

AF ; MOVE 8-BIT PARAMETER TO STACK SP ; REMOVE EXTRANEOUS BYTE

SUBR ;EXECUTE SUBROUTINE

HL,3 ;CLEAN PARAMETERS FROM STACK

The first three instructions of the calling program could be replaced with two DEC SP instructions, and the last three instructions with three INC SP instructions. Note that only 16-bit register pairs can be moved to or from the stack. Remember, AF consists of the accumulator (MSB) and the flags (LSB).

ssss 1 - - - 1 Stack Pointer No values are placed in the locations.

The initial contents of the stack pointer are ssss.

E7:rt;t~~~;

{

Figure 1·8. The stack before and after assigning NRESL T empty locations for results

CHAPTER 1. GENERAL PROGRAMMING METHODS

51

The initial contents of the stack pointer are ssss.

Figure 1·9. The effect of a subroutine on the stack

Im Dokument Assembly Language Subroutines (Seite 59-64)