1

I'm using the ca65 assembler (https://cc65.github.io/doc/ca65) to run my project. I know 6502 has SP register points to low byte of stack position ($01SP).

But I don't know how actually (sp) works in code.

In ca65's runtime it has func to push A into a stack:

pusha:  ldy     sp              ;
        beq     @L1             ;
        dec     sp              ; 
        ldy     #0              ;
        sta     (sp),y          ;
        rts                     ;

But why doesn't it push value into the stack? Why does it save value into a memory from 0?

For example, if I do this code:

ldx #$ff
txs
lda #$cc
jsr pusha

I expected to see $cc in stack's memory location, but it saved $cc into memory under stack.

Result I had from logs of emulator where A,X,Y,SP - registers, OP - current opcode, PC - program counter, SPData - stack's data, and MemData, it's RAM:

;Load stack pointer into X    
LDX 8001, A=0, X=0, Y=0, SP=0, addr=ff, op=a2, PC=8002, SPData=0,0,0,0,0,0,0,0,0, MemData=0,0,0,0,0,0,0,0,0
;Save stack pointer from X to SP
TXS 0, A=0, X=ff, Y=0, SP=0, addr=0, op=9a, PC=8003, SPData=0,0,0,0,0,0,0,0,0, MemData=0,0,0,0,0,0,0,0,0
;Load $CC into A
LDA 8004, A=0, X=ff, Y=0, SP=ff, addr=cc, op=a9, PC=8005, SPData=0,0,0,0,0,0,0,0,0, MemData=0,0,0,0,0,0,0,0,0
;Jump to ca65's runtime func "pusha" to save A into stack
JSR 810c, A=cc, X=ff, Y=0, SP=ff, addr=a4, op=20, PC=8008, SPData=0,0,0,0,0,0,0,0,0, MemData=0,0,0,0,0,0,0,0,0
LDY 0, A=cc, X=ff, Y=0, SP=fd, addr=0, op=a4, PC=810e, SPData=0,7,80,0,0,0,0,0,0, MemData=0,0,0,0,0,0,0,0,0
BEQ 8117, A=cc, X=ff, Y=0, SP=fd, addr=c6, op=f0, PC=8110, SPData=0,7,80,0,0,0,0,0,0, MemData=0,0,0,0,0,0,0,0,0
DEC 1, A=cc, X=ff, Y=0, SP=fd, addr=0, op=c6, PC=8119, SPData=0,7,80,0,0,0,0,0,0, MemData=0,0,0,0,0,0,0,0,0
DEC 0, A=cc, X=ff, Y=0, SP=fd, addr=0, op=c6, PC=811b, SPData=0,7,80,0,0,0,0,0,0, MemData=0,ff,0,0,0,0,0,0,0
STA 0, A=cc, X=ff, Y=0, SP=fd, addr=ff, op=91, PC=811d, SPData=0,7,80,0,0,0,0,0,0, MemData=ff,ff,0,0,0,0,0,0,0
;here I want to see $cc into SPData, but it was pushed into MemData
RTS 0, A=cc, X=ff, Y=0, SP=fd, addr=cc, op=60, PC=811e, SPData=0,7,80,0,0,0,0,0,0, MemData=cc,ff,0,0,0,0,0,0,0

Console command to build is:

    ca65 --cpu 6502 -I ${HOME}/cc65/asminc -U arch/boot.s -o arch/boot.o
Andy
  • 21
  • 3
  • 6
    Apparently the runtime has set up a separate stack. The `sp` you see in the source is not the `SP` register of the cpu. It's a 16 bit variable in the zero page. – Jester Jun 14 '21 at 10:20
  • 1
    So, they have different sense, thanks you a lot! – Andy Jun 14 '21 at 18:38
  • 2
    In a 6502 you do not have direct access to sp (you can do txs or tsx) To push a value on the stack you use pha and to pull pla. – some Jun 14 '21 at 20:19
  • 2
    If it helps at all as to context, C is usually implemented such that it needs to access a bunch of values _relative to_ a current stack pointer. So there's a big blob of memory at the top of the stack that it accesses randomly. The 6502 doesn't offer that sort of access to the stack. That combined with the fact that the hardware stack is really small by C standards means that C compilers for the 6502 tend to implement a software stack. Also the CPU register is usually just called `S`, not `SP`, if that helps. – Tommy Jun 14 '21 at 23:23

1 Answers1

1

You are right that the 6502 has a hardware stack in memory locations $0100 through $01ff. There is a stack pointer in the 6502, one byte wide, which is called S.

But the ca65 runtime uses also a separate stack, implemented in a different way. It has a zero-page variable, called sp, which points to a different area. This area is where pusha stores A.

Lorraine
  • 1,189
  • 14
  • 30