如何将寄存器加载到自身的指令有什么作用?

14

在查看Gameboy的指令集时,我遇到了诸如以下指令:

LD A, A
LD B, B
LD C, C
LD D, D

...

这个表格中,每条指令都有自己的操作码,这让我觉得它们由于可能的操作码数量的限制而非常重要。

起初我认为它可能是对该寄存器中的指针进行解引用并将值存储到该指针中(就像这个问题中的),但在一个模拟器中,实现了LD A, A

Z80._r.a = Z80._r.a

它们似乎对处理器状态没有影响(只是将寄存器设置为它们自己的值),执行所需的周期数与NOP相同。

为什么这些操作码被包含在指令集中,它们有什么作用?


4
我猜它们的唯一目的是通过避免特殊情况来使指令解码器更容易实现。某些位始终意味着“A”,就是这样。 - Bo Persson
2
“nop”是与这些中的一个相同的操作码吗?在x86上,一字节的NOP 0x90是一字节的“xchg”-with-ax短格式0x90..0x97的“xchg ax,ax”特殊情况。 - Peter Cordes
1
@PeterCordes 不,NOP操作码是0x00,其他所有操作码都是唯一的。这里是列表 - Spooze
2
稍微澄清一下,在向后兼容的 eZ80 上,这些指令实际上用于特殊目的(基本上是为了从例程的其余部分中发出信号,以表明何时应使用特殊模式中的指令)。 - Zeda
4
@PeterCordes,然而将00设为NOP是很重要的:在一些机器如ZX80中,视频逻辑通过强制数据总线低电平来使CPU执行NOP指令作为地址生成器。 - Stefan Paul Noack
显示剩余4条评论
2个回答

15

如果您检查,它们会简化解码单元。

7F LD A,A
78 LD A,B
79 LD A,C

对决

47 LD B,A
40 LD B,B
41 LD B,C

对比

4F LD C,A
48 LD C,B
49 LD C,C

你会注意到,底部的三位用于保留源寄存器(值为0-7,对应B,C,D,E,H,L,(HL),A),然后是3位目标寄存器,再次具有相同的0-7含义(因此0与0创建LD B,B),而顶部的两个位01选择了LD指令,快速浏览时不确定是否完全解密。

因此,人们也会期望76代表LD (HL),(HL),这甚至比LD A,A更没有意义,因此需要特殊逻辑来捕获该指令并执行HALT

所以这就是指令译码器简单化的问题,使用相同的位模式来选择源/目标寄存器,并且不添加更多的晶体管以避免处理同一寄存器的情况,除了(HL),(HL)(可能在内部在源和目标上都失败,需要访问内存,因此硬件设计中的额外“逻辑”可能非常简单)。

请记住,早期的CPU通常是手工设计的,必须保持总晶体管数量较低,以便适合芯片并且可以手工绘制电路并验证其正确性。

编辑:Z80大约有8500个晶体管,您可以查看:https://en.wikipedia.org/wiki/Transistor_counthttps://en.wikipedia.org/wiki/Zilog_Z80... GameBoy有一个稍微修改过的Z80,但是总晶体管数量将非常接近原始值,尽管我没有搜索确切的值,并且我不确定任天堂向未来扩展了多少,也许他们甚至可以负担起像20-50k这样的东西,但我怀疑。


补充说明:最近我阅读了有关俄罗斯Sinclair ZX Spectrum克隆机的文章,它们是经过大量修改的机器,添加了额外的功率、内存和功能...其中一些使用这些ld same,same操作码来控制DMA传输,在这些机器上,使用它们作为nop的代码可能无法正常执行。虽然这与GameBoy无关,但如果您面向其中之一的“Sprinter”或类似的俄罗斯ZX克隆机的二进制目标,并且在反汇编中发现其中之一,请不要将其自动视为nop,它们可能是实际执行某些操作的有效代码(最有可能是与DMA相关的)。


5
这些奇怪的NOP指令可以追溯到原始祖先处理器Intel 8008。在那个芯片中,它们只是寄存器移动指令的实现结果。MOV A,A等指令简化了指令解码器并节省了硅空间。
从8080到Z80(以及更高版本),这些指令的使用成为保持向后兼容性所必需。它们甚至以MOV AL,AL等形式生存于x86世界中。
因此,大多数现代台式机仍然支持这些奇怪的指令。
注意:描述Intel机器时我使用了Intel助记符。请放心,这些与Zilog助记符汇编出相同的二进制代码。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接