GBZ80 - 代码缺点

时间:2017-03-02 21:58:47

标签: machine-code z80 gameboy

这种gbz80 - IF statements

的词干

我有一个循环0x167次的代码,写入屏幕。 我想要发生的是脚本循环三次。

我的剧本:

    d322 21A0C3 LD HL,C3A0h
    d323 016801 LD BC,0168h
    d324 110300 LD DE,0003h
    d325 00     NOP
    .
    .
    .
    d330 0B     DEC BC
    d331 75     LD (HL),L
    d332 00     NOP
    d333 23     INC HL
    d334 00     NOP
    .
    .
    .
    d33f 78     LD A,B
    d340 B1     OR C
    d341 C22BD3 JP NZ,D32Bh
    d344 7A     LD A,D
    d345 B3     OR E
    d346 1B     DEC DE
    d347 00     NOP
    d348 00     NOP
    d349 C22BD3 JP NZ,D32B
    d34c C9     RET

现在,它不再停留在应有的位置,而是继续进一步损坏内存,直到达到d325并导致脚本崩溃。你可能会说,我试图用DE作为循环的计数器。

请解释一下你的答案,我对此仍然很乏味。

2 个答案:

答案 0 :(得分:0)

我的阅读就是你:

Set HL = 0xC3A0, BC = 0x0168, DE = 0x0003

do {
  ... something you've omitted ...
  do {
    bc--
    [l] = hl
    hl++
  } while(bc)

  was_positive = (DE > 0)
  DE--
} while(was_positive)

因此外部循环将发生四次次,因为模式将是:

  • 执行内循环(* 1)
  • 比较3到0
  • 执行内循环(* 2)
  • 比较2到0
  • 执行内循环(* 3)
  • 比较1到0
  • 执行内循环(* 4)
  • 比较0到0,不再更大,退出

可能你想在比较之前做DEC?它是将DE与零进行比较的LD A, D / OR E - 如果其位的确切为零,则表示它为零 - 后续的减量不会改变您已经计算的结果

在这种情况下,您将获得0x0168 + 4 * 0x10000次迭代= 0x40168次迭代。哪个甚至可能不是你想要的?这意味着你会多次覆盖内存中的每个地址。即使您的代码在ROM中是安全的,也会造成大量浪费的代码。

如果您打算循环3 * 0x0168次,那么还要记得重新加载BC。你只需让它下溢到0xffff并恢复。考虑切换初始加载的顺序,使BC最后,并更改外部分支以跳回到加载它的位置。

答案 1 :(得分:0)

问题是您在设置标志后递减DE。代码的关键部分是:

LD A,D
OR E
DEC DE
JP NZ,D32B

将其更改为:

DEC DE
LD A,D
OR E
JP NZ,D32B

外部循环将运行3次而不是4.注意BC循环正确处理并执行0x168次,而不是0x167,因此您可能想要更改它。

Z-80上的16位计数器很笨拙,因为16位递减不会设置任何标志。这就是为什么你需要代码将两个寄存器组合在一起作为在16位对等于零时设置Z标志的方法。

由于您只需要3次迭代,您可以使用一个8位寄存器并写入:

LD E,3
...
DEC E
JP NZ,D32B

正如Tommy的回复中所述,您还需要在内循环中重新加载BC,方法是将LD BC,0x168移至D32B。