在 6502 汇编器中编写子程序的最佳方法?

use*_*996 4 assembly c64 6502 calling-convention

我是汇编程序新手,所以这是一个简单的问题:

我的自定义子例程更改XYA寄存器。他们操纵这些来产生期望的结果。在例程启动时将这些值推入堆栈并在之前恢复它们是一个好主意吗RTS

我的意思是,这样我就可以编写可以从任何地方调用的例程,而不会弄乱“状态”或影响其他例程。但是这样使用栈可以吗?或者有更好的方法来做到这一点吗?

ten*_*dim 5

但是这样使用栈可以吗?或者有更好的方法来做到这一点吗?

绝对地; BASIC 一直在这样做,内核中的许多例程也是如此。

但是,这个问题没有正确的答案,至少可以归结为速度、便携性和风格。

  • 如果您经常使用堆栈,则需要考虑一些速度。开始时是典型的情况pha txa pha tya pha,然后反向 ( pla tay pla tax pla) 会占用堆栈的 3 个字节,并由于 2 x 5 操作而增加一些周期时间

  • 您可以使用零页,但这会消除不同机器之间的一些可移植性;VIC-20、C64、C128,跨平台的空闲零页地址可能不一样。并且您的例程不能在不先退出的情况下“多次”调用(例如,无递归),因为如果在活动状态下调用它,它将用新值覆盖零页。但是,您不需要使用零页......

  • ...因为您可以创建自己的内存位置作为代码的一部分:

    myroutine = *
        ; do some stuff..
        rts
    
    mymem =*
        .byt 0, 0, 0
    
    Run Code Online (Sandbox Code Playgroud)
  • 这样做的缺点是你的例程只能被调用“一次”,否则后续调用将覆盖你的存储区域(例如不允许递归!!,与之前相同的问题!)

  • 您可以编写自己的迷你堆栈

      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
    
    Run Code Online (Sandbox Code Playgroud)
  • 这还有一个额外的好处,即您现在拥有 3 个虚拟堆栈( 、 、 各一个.A.X.Y但需要付出一定的代价(不完全是一个快速例程)。因为我们使用的是SEIand CLI,所以如果从中断处理程序中执行此操作,您可能需要重新考虑这一点。但这也可以保持“真正的”堆栈干净,并使可用空间增加三倍以上。