我可以通过一些16位魔术把它变成一个循环吗?

时间:2014-02-05 04:18:05

标签: assembly 6502 c64

我现在开始使用6502程序集,并且在绕过需要处理大于8位的数字的循环时遇到问题。

具体来说,我想循环一些内存位置。在伪c代码中,我想这样做:

    // Address is a pointer to memory
    int* address = 0x44AD;
    for(x = 0; x < 21; x++){
        // Move pointer forward 40 bytes
        address += 0x28;
        // Set memory location to 0x01
        &address = 0x01;
    }

从地址$44AD开始,我想将$01写入ram,然后向前跳转$28,将$01写入其中,然后向前跳转$28再次,直到我完成了20次(写的最后一个地址是$47A5)。

我目前的方法是循环展开,编写起来很繁琐(尽管我认为汇编程序可以更简单):

ldy #$01
// Start from $44AD for the first row, 
    // then increase by $28 (40 dec) for the next 20
sty $44AD
sty $44D5
sty $44FD
    [...snipped..]
sty $477D
sty $47A5

我知道绝对寻址(使用累加器而不是Y寄存器 - sta $44AD, x),但这只能给出0到255之间的数字。我真正想要的是这样的:

       lda #$01
       ldx #$14 // 20 Dec
loop:  sta $44AD, x * $28
       dex
       bne loop

基本上,从最高地址开始,然后循环。问题是$ 14 * $ 28 = $ 320或800 dec,这比我实际存储在8-bit X寄存器中的要多。

有优雅的方法吗?

2 个答案:

答案 0 :(得分:8)

6502是一个8位处理器,因此您无法完全在寄存器中计算16位地址。你需要间接通过第0页。

      // set $00,$01 to $44AD + 20 * $28 = $47CD
      LDA #$CD
      STA $00
      LDA #$47
      STA $01

      LDX #20  // Loop 20 times
      LDY #0
loop: LDA #$01 // the value to store
      STA ($00),Y // store A to the address held in $00,$01
      // subtract $28 from $00,$01 (16-bit subtraction)
      SEC
      LDA $00
      SBC #$28
      STA $00
      LDA $01
      SBC #0
      STA $01
      // do it 19 more times
      DEX
      BNE loop

或者,您可以使用自修改代码。这是一种可疑的技术,但在6502等嵌入式处理器上很常见,因为它们非常有限。

      // set the instruction at "patch" to "STA $47CD"
      LDA #$CD
      STA patch+1
      LDA #$47
      STA patch+2

      LDX #20  // Loop 20 times
loop: LDA #$01 // the value to store
patch:STA $FFFF
      // subtract $28 from the address in "patch"
      SEC
      LDA patch+1
      SBC #$28
      STA patch+1
      LDA patch+2
      SBC #0
      STA patch+2
      // do it 19 more times
      DEX
      BNE loop

答案 1 :(得分:2)

复制1k数据的更有效方法:

    ldy #0
nextvalue:
    lda address, y
    sta address, y

    lda address+$100, y
    sta address+$100, y

    lda address+$200, y
    sta address+$200, y

    lda address+$300, y
    sta address+$300, y
    iny
    bne nextvalue 

很少注意到:

  • 更快,因为循环开销减少了。由于更多命令,占用的空间更多。

  • 如果您使用的汇编程序支持宏,您可以轻松地对其进行配置,代码处理的块数。

可能与此没有100%的相关性,但这是另一种长度超过255循环的方法:

nextblock:
    ldy #0
nextvalue:
    lda address, y
    iny
    bne nextvalue

;Insert code to be executed between each block here:

    dec numblocks
    bpl nextblock

numblocks:
    .byte 3

很少注意到:

  • 目前,代码并没有真正做任何有意义的事情,而是运行循环“numblocks”次。 “添加你自己的代码”:-)(我常常将它与一些自修改代码一起使用,例如增加sta,y地址)

  • bpl可能很危险(如果你不知道它是如何工作的),但在这种情况下运行良好(但如果numblocks地址包含足够大的值,则不会)

  • 如果您需要再次执行相同的代码,则需要重新设置numblocks。

  • 通过将numblocks置于零页面可以使代码更快一些。

  • 如果其他东西不需要(通常是这样),你可以使用X寄存器而不是内存位置。