Beruflich Dokumente
Kultur Dokumente
The stack is a last-in-first-out (LIFO) data structure. It is a queue with only one end; that is new items enter at the same point as old items leave. Items leave a stack in the reverse order in which they arrive. A LIFO queue is the same as a stack in conventional English. If you pile books on top of each other and then remove them from the top, it behaves exactly like a stack. In a computer a stack can be used in many ways. However, we are interested in the following three applications of the stack: 1. Storing subroutine return addresses 2. Passing parameters from a program to a subroutine 3. Providing temporary storage (local workspace) in a subroutine. The following diagram illustrates the 68Ks stack. The stack is a data structure that can be located in any region of memory. The stack grows up towards low addresses; that is, the address of an item at the top of the stack is lower than the address of an item at the bottom of the stack. Address register A7 is used as the stack pointer. It should not be used for any other purpose. When an item enters the stack it is said to be pushed on the stack. When an item leaves the stack, it is said to be pulled off the stack.
The 68Ks stack may contain word (16-bit) items or longword (32-bit) items. You may not push a byte element on the stack. This is a hardware limitation imposed by the 68Ks bus mechanism. The word in D0 is pushed on the stack by the instruction MOVE.W D0,(A7). This means that the contents of the stack pointer are decremented by 2 to point at the next free word above the top of stack. Then the contents of D0 are stored in this location. This location now becomes the new top of stack. The next figure shows the state of the stack after executing MOVE.W D0,-(A7) and MOVE.L D1,-(A7). These instructions first push the low-order word of D0 and then the entire value of D1. The value of the stack pointer is first decremented by 2 (to push a word) and then decremented by 4 (to push a longword).
The inverse operation to pushing data on the stack is to pull it off the stack. The instruction MOVE.W (A7)+,D0 pulls the word off the top of the stack and moves the stack pointer down by 2. Consider the following examples. MOVE.L MOVE.W MOVE.L MOVE.W MOVE.W (A7)+,D7 #123,-(A7) #123,-(A7) Temp4,-(A7) 8(A7),-(A7) ;Pull a longword off the top of the stack and put it in D7 ;Push the value 123 on the stack as a 16-bit word. ;Push the value 123 on the stack as a 32-bit longword. ;Push the contents of location Temp4 on the stack. ;Push the word 8 bytes below the top of the stack on to the stack.
Subroutine Call and Return In 68K assembly language you call a subroutine by using the instruction BSR XYZ where XYZ is the name of the subroutine. This symbolic name corresponds to the address of the first instruction in the subroutine. After the subroutine has been executed, you return to the point (i.e., instruction) immediately following the subroutine call. The return address is automatically saved on the stack as a longword. You return from a subroutine by using the RTS instruction. The processor pulls the top longword off the stack and puts it in the program counter to force a return to the calling point. Returning from a subroutine call involves pulling the return address off the stack. Consider the following. . BSR . . . . . RTS XYZ ;Call XYZ ;This is where your return ;This is the subroutine ;Return to point immediately after the call
XYZ
The next diagram demonstrates a subroutine call and a subroutine return. Calling a subroutine pushes the return address onto the stack. Whenever you enter a subroutine, the longword at the top of the stack is always the return address.
Passing a Parameter to a Subroutine When you call a subroutine, you often have to pass parameters to the subroutine. In a high level language you might call subroutine XYZ with parameters P and Q by XYZ(P,Q). In a low-level language, you may push the parameters on the stack immediately before calling the subroutine. The next diagram shows the effect of pushing a parameter on the stack before calling a subroutine. State (c) shows the situation after the subroutine has been called. Note that the parameter is 4 bytes below the top of the stack. You can get this parameter in D7 by means of MOVE.W 4(A7),D7. This instruction means move the word 4 bytes below the word pointed at by the stack pointer into D7.
ADD3
;Get N2 under the return address ;Get N1 under N2 ;Do the addition ;Do the multiplication to get 3(N1+N2) ;Return the result in the N2 slot on the stack ;Now go home ;Start of data area ;Dummy data for N1 ;Dummy data for N2
N1 N2
The next diagram demonstrates the state of the stack before the execution of the program, immediately before the subroutine call, and immediately after it. As you can see, parameters N1 and N2 are at 6 bytes and 4 bytes below the stack pointer, respectively, when in the subroutine ADD3.
Note that the notation MOVE.W 4(A7),D2 means move the word that is 4 bytes below that pointer at by address register A7 into data register D2. On return from the subroutine, parameters N2 and N1 are at the top of the stack. Executing MOVE.W (A7)+,D0 pulls the result that we put in N2 off the stack. This leaves the stack with parameter N1 at the top. We no longer need N1 and we can reclaim its stacks space by a dummy pull such as MOVE.W (A7)+,D1. However, we dont want this parameter. We can simply adjust the stack pointer by moving it down 2 bytes with ADD.L #2,A7. Note that a real programmer would write LEA 2(A7),A7 which does the same thing.
ABC
. RTS
;Return
Note that retrieving a parameter by reference is a two step operation. The first part is to get the address and the second part is to get the value pointed at by that address. Note also that we used a .L operation to retrieve the address and a .W operation to retrieve the value of the parameter. All addresses are longword, whereas parameters may be bytes, words, longwords or anything you want.
Important Points
1. The stack is a last-in-first out queue maintained by the computer. The 68K uses address register A7 to point at the top of the stack. You can write A7 or SP in 68K programs; for example: MOVE.W 24,-(SP) 2. You can push a word or longword on the stack by MOVE.W source,-(A7) where source is any valid addressing mode. 3. You can pull a word off the stack by MOVE.W (A7)+,destination where destination is any valid addressing mode. 4. Making an error with a stack operation will invariably crash a program. 5. When you call a subroutine, the return address is pushed on the stack. When you return from the subroutine, the return address is pulled. 6. You return from a subroutine with an RTS instruction. You NEVER jump out of a subroutine directly with a BRA or JMP instruction. Doing this would leave the return address on the top of the stack. 7. You can call a subroutine with BSR or JSR (branch to subroutine and jump to subroutine). These two instructions have the same effect. The difference between them lies in the addressing modes they support. 8. The instruction PEA pushes an address on the stack and is used to pass a parameter by reference (address).