9

我现在开始使用 6502 Assembly,并且在处理需要处理大于 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我想写入$01ram 的地址开始,然后向前跳转$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 位 X 寄存器中的要多。

有没有一种优雅的方式来做到这一点?

4

2 回答 2

10

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

      // 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
于 2014-02-05T05:32:49.090 回答
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 寄存器而不是内存位置。

于 2014-05-07T18:43:13.210 回答