A stack is a programming concept which stores variables in "FILO" (First In, Last Out) order.
Imagine, if you would, a stack of plates. You can only access the top plate in the stack, to reach the plate below it, you must first remove the top plate so that the plate below it is the new top.
A programming stack works in such a fashion. Numbers are "pushed" onto the stack (like adding a new plate on top), and then can later be "pulled" off the stack (like taking the top plate off). When you pull from the stack, you will receive the number most recently pushed.
To demonstrate this, here's some examples with PHA, and PLA. If you're unfamiliar with these instructions, PHA just pushes the value in A onto the stack, and PLA pulls the top value off the stack and puts it in A.
Code:
; assume for this example, that here, the stack is empty:
; Stack -> [empty]
LDA #$20
PHA ; push $20 onto the stack
; Stack -> $20
LDA #$15
PHA
; Stack -> $15 (top)
; $20 (bottom)
LDA #$3F
PHA
; Stack -> $3F
; $15
; $20 (bottom)
LDA #$00 ; fill A with garbage
PLA ; pull from the stack, put in A
; Stack -> $15 (top)
; $20 (bottom)
;
; A is now $3F -- the value pulled from the top of the stack
; though it was briefly set to $00 -- I only did that to show that PLA
; will change the value in A. After that PLA, A will no longer be $00
PLA
; Stack -> $20 (top & bottom)
;
; A is now $15
Interrupts (NMI, IRQ), automatically push the old PC and status flags to the stack (so that when you RTI, status flags are restored to how they were before the NMI). However, A, X, and Y are NOT automatically pushed, so they will retain their values through an interrupt. This can be fatal if an NMI occurs during some calculations:
Code:
somecode:
CLC
LDA #$10
ADC #$10
STA $00
RTS
nmi:
LDA #$00
RTI
if you look at 'somecode', you'll see that it will add $10 and $10 together, then store the result ($20) at address $00.
BUT! What happens if the NMI occurs right between that LDA and ADC command! The CPU will do the following:
Code:
CLC
LDA #$10
-- NMI OCCURING, jump to NMI code --
LDA #$00
RTI
-- RTI returns to area before NMI occured, continue with original code --
ADC #$10
STA $00
RTS
now, instead of adding $10 and $10 together, it's actually adding $00 and $10 together!
Because of this it's common practice for games to back up A X and Y in an interrupt, then restore them before RTI. This way A X and Y will not be changed by the interrupt.
You've probably seen this code:
Code:
nmi:
PHA ; push A onto the stack (back it up)
TXA
PHA ; push X onto the stack
TYA
PHA ; push Y onto the stack
; blah blah, do NMI stuff here
PLA
TAY ; pull Y off the stack (restore the backed-up version)
PLA
TAX ; pull X off the stack
PLA ; pull A off the stack
RTI
As for why games set the stack pointer to $FF at startup -- this is due to the stack being "upside down" and games want the bottom of the stack to start at the VERY bottom to allow for the most stack space possible. I'm too lazy/tired to explain it any further than this, maybe someone else will field this part.