1

这种gbz80 的词干 - IF 语句

我有一个循环 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 作为循环计数器。

请解释您的答案,我对此仍然很无聊。

4

2 回答 2

1

我的阅读是你:

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?它将LD A, D / OR EDE 与零进行比较——如果恰好设置了零位,则您断言它为零——随后的递减不会改变您已经计算的结果。

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

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

于 2017-03-03T17:16:55.547 回答
1

问题是您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 位对等于 0 时,您需要将代码对两个寄存器进行或运算,以设置 Z 标志。

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

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

正如 Tommy 的回复中所指出的,您还需要BC在内部循环中重新加载,例如将 移动LD BC,0x168到 D32B。

于 2017-03-03T19:28:21.143 回答