home   |   stacks treatise index   |   1. Intro: stack basics   |   2. subroutine return addresses & nesting   |   3. interrupts   |   4. virtual stacks   |   5. stack addressing   |   6. passing parameters   |   7. inlined data   |   8. RPN operations   |   9. RPN efficiency   |   10. 65c02 added instructions   |   11. synth instructions w/ RTS/RTI/JSR   |   12. where-am-I routines   |   13. synthesizing 65816 stack instructions   |   14. local variables, environments   |   15. recursion   |   16. enough stack space?   |   17. forming program structures   |   18. stack potpourri   |   19. further reading   |   A: StackOps.ASM   |   B: 816StackOps.ASM   |   Appendix C


Does the 6502 have enough stack space?

A common criticism of the 6502 is that the stack space is so limiting (or at least perceived to be).  A few higher-level languages (notoriously Pascal) do put very large pieces of data and even entire functions and procedures on the stack instead of just their addresses.  For most programming though, the 6502's stack is much roomier than you'll need for most things, especially assembly language.  When you know you're accessing the stacks constantly but don't know what the maximum depth is you're using, the tendency is to go overboard and keep upping your estimate, "just to be sure."

I did this for years myself, and finally decided to do some tests to find out.  I filled the 6502 stack area with a constant value (maybe it was 00—I don't remember), ran a heavy-ish application with all the interrupts going too, did compiling, assembling, and interpreting while running other things in the background on interrupts, and after a while looked to see how much of the stack area had been written on.  It wasn't really much—less than 20% of each of page 1 (return stack) and page 0 (data stack).  This was in Forth, which makes heavy use of the stacks.  The IRQ interrupt handlers were in Forth too, although the software RTC (run off a timer on NMI) was in assembly language.

I understand that in EhBASIC for the 6502, FOR (in a FOR...NEXT loop) puts 16 bytes on the hardware stack.  That seems extreme to me; but I won't condemn EhBASIC just for that, as I looked into it years ago and it appeared to be an absolutely outstanding BASIC for the 6502.  Bruce Clark says on the 6502.org forum that of the three varieties of BASIC he listed further up (Apple 1 BASIC and Integer BASIC are cut from the same cloth, as are Applesoft and EhBASIC), only the Applesoft/EhBASIC variety put intermediate values on the hardware stack.  The Apple-1/Integer BASIC variety and Tiny BASIC use a Forth-like data stack, even using ZP,X addressing.  For completeness, KIM-1 Focal uses a data stack that can span multiple pages (using (ZP),Y addressing).

Update, 6/5/17: BigEd who's active on the 6502.org forum, the AnyCPU forum, the Startdot forum, and others, says the Acorn BBC Micro's BASIC took a ton of stack space for

    PRINT (1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1)))))))))))

or even

    PRINT 1+((((((((((((1))))))))))))

putting 14 bytes on the stack for each layer of parentheses, with a very stack-hungry recursive parser.  Again though, that's BASIC.  I think you'd have to try awfully hard to take anywhere near that in assembly, or even Forth which exposes the stacks directly to the programmer.

See the end of section 14 on local variables and environments, the last few paragraphs, about some possibilities for if you want to put entire arrays or other large sets of data on a stack when there may not be enough room for them.

There is no warning of overflowing or underflowing the stack, or even imminent over/underflow.  If underflow happens, you have a serious bug you need to fix; but overflow may be a semi-innocent result of running too much nesting, especially with a recursive subroutine, or of putting unexpectedly large sets of data on the stack when there wasn't enough room left.  Again, normally you'll have plenty of stack space and no protections are needed; but TSX, CPX can be used to check the depth of the hardware stack.  In the case of a ZP data stack, the pointer is X, and again you can check that easily.  Section 18 ("Stacks Potpourri") has a section on measuring stack depth, and valid reasons for doing so.

If you wanted to set up a multitasking system, and give each task its own portion of the stack space, you could do three tasks with no trouble at all, perhaps six or eight with care.  (Remember that the above, using less than 20% of the stack space, was in a sense already multitasking.)  The 65816 works much better for multitasking systems anyway though, and it has a 16-bit stack pointer, 16-bit index registers, and a relocatable direct page, so it's like every task can have its own zero page as well as a hardware stack space of many pages if desired.  Section 18 has brief additional discussion of stack considerations in a multitasking OS.

15. recursion <--Previous   |   Next--> 17. forming program structures

last updated Jan 21, 2023