user2297996
user2297996

Reputation: 1584

Best way of writing subroutines in 6502 Assembler?

I'm new to assemblers, so here is a simple question:

My custom subroutines change the X, Y, and A registers. They manipulate these to produce the desired results. Is it a good idea to push these values to the stack when the routine starts and restore them before RTS?

I mean, this way I can write routines which can be called from anywhere without messing up the "state" or affecting other routines. But is it OK to use the stack this way? Or is there a better way to do this?

Upvotes: 5

Views: 1479

Answers (1)

tendim
tendim

Reputation: 477

But is it OK to use the stack this way? Or is there a better way to do this?

Absolutely; BASIC does it all the time, as do many routines in the kernal.

But, there is no right answer to this, it comes down to at least speed, portability, and style.

  • If you use the stack a lot, there are some speed considerations. Your typical pha txa pha tya pha at the start, and then the reverse (pla tay pla tax pla) eats up 3 bytes of your stack, and adds in some cycle time due to the 2 x 5 operations

  • You could use zero page, but that takes away some portability between different machines; VIC-20, C64, C128, the free zero page addresses may not be the same across platforms. And your routine can't be called "more than once" without exiting first (e.g. no recursion) because if it is called while it is active, it will overwrite zero page with new values. But, you don't need to use zero page...

  • ...because you can just create your own memory locations as part of your code:

    myroutine = *
        ; do some stuff..
        rts
    
    mymem =*
        .byt 0, 0, 0
    
  • the downside to this is that your routine can only be called "once", otherwise subsequent calls will overwrite your storage areas (e.g. no recursion allowed!!, same problem as before!)

  • You could write your own mini-stack

      put_registers =*
         sei ; turn off interrupts so we make this atomic
         sty temp
         ldy index
         sta a_reg,y
         stx x_reg,y
         lda temp
         sta y_reg,y
         inc index
         cli
         rts
    
      get_registers =*
         sei ; turn off interrupts so we make this atomic
         dec index
         ldy index
         lda y_reg,y
         sta temp
         lda a_reg,y
         ldx x_reg,y
         ldy temp
         cli
         rts
    
      a_reg .buf 256
      x_reg .buf 256
      y_reg .buf 256
      index .byt 0
      temp  .byt 0
    
  • This has the added benefit that you now have 3 virtual stacks (one for each of .A, .X, .Y), but at a cost (not exactly a quick routine). And because we are using SEI and CLI, you may need to re-think this if doing it from an interrupt handler. But this also keeps the "true" stack clean and more than triples your available space.

Upvotes: 5

Related Questions