ELET2100 - Microprocessors I
The stack is one of the most important things you must know when programming. Think of the stack as a deck of cards. When you put a card on the deck, it will be the top card. Then you put another card, then another. When you remove the cards, you remove them backwards, the last card first and so on. The stack works the same way, you put (push) words (addresses or register pairs) on the stack and then remove (pop) them backwards. That's called LIFO, Last In First Out.
The 8085 uses a 16 bit register to know where the stack top is located, and that register is called the SP (Stack Pointer). There are instructions that allow you to modify it’s contents but you should NOT change the contents of that register if you don't know what you're doing!
PUSH & POP
As you may have guessed, push and pop “pushes” bytes on the stack and then takes them off. When you push something, the stack counter will decrease with 2 (the stack "grows" down, from higher addresses to lower) and then the register pair is loaded onto the stack. When you pop, the register pair is first lifted of the stack, and then SP increases by 2.
N.B: Push and Pop only operate on words (2 bytes ie: 16 bits).
You can push (and pop) all register pairs: BC, DE, HL and PSW (Register A and Flags). When you pop PSW, remember that all flags may be changed. You can't push an immediate value. If you want, you'll have to load a register pair with the value and then push it. Perhaps it's worth noting that when you push something, the contents of the registers will still be the same; they won't be erased or something. Also, if you push DE, you can pop it back as HL (you don't have to pop it back to the same register where you got it from).
The stack is also updated when you CALL and RETurn from subroutines. The PC (program counter which points at the next instruction to be executed) is pushed to the stack and the calling address is loaded into PC. When returning, the PC is loaded with the word popped from the top of the stack (TOS).
So, when is this useful? It's almost always used when you call subroutines. For example, you have an often used value stored in HL. You have to call a subroutine that you know will destroy HL (with destroy I mean that HL will be changed to another value, which you perhaps don't know). Instead of first saving HL in a memory location and then loading it back after the subroutine, you can push HL before calling and directly after the calling pop it back. Of course, it's often better to use the pushes and pops inside the subroutine. All registers you know will be changed are often pushed in the beginning of a subroutine and then popped at the end, in reverse order! Don't forget - last in first out. If you want to only push one 8 bit register, you still have to push it's "friend". Therefore, be aware that if you want to store away D with pushing and popping, remember that E will also be changed back to what it was before. In those cases, if you don't want that to happen, you should try first to change register (try to store the information in E in another register if you can) or else you have to store it in a temporary variable.
Before executing a program, you should keep track of your pushes and pops, since they are responsible for 99% of all computer crashes! For example, if you push HL and then forget to pop it back, the next RET instruction will cause a jump to HL, which can be anywhere in the ROM/RAM and the ccomputer will crash. Note however, it’s also a way to jump to the location stored in HL, but then you should really use the JMP instruction, to do the same thing.
Push and pop doesn't change any flags, so you can use them between a compare and jump instructions, depending on a condition, which is often very useful.