14

While looking through the Gameboy's instruction set, I came across instructions such as:

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

...

Each of these instructions has it's own opcode in this table, which makes me think they are of some importance due to the restrictions on the number of possible opcodes.

I first thought that it might be dereferencing a pointer in that register and storing the value at that pointer (like in this question), but in an emulator, LD A, A is implemented as:

Z80._r.a = Z80._r.a

They seem to have no effect on the state of the processor (just set registers to their own value) and take the same number of cycles as a NOP to execute.

Why are these opcodes included in the instruction set and what purpose do they serve?

Spooze
  • 378
  • 1
  • 10
  • 4
    I guess their only purpose is to make the instruction decoder easier to implement by avoiding special cases. Some bits always mean `A`, and that's it. – Bo Persson May 05 '18 at 09:31
  • 2
    Is `nop` the same opcode as one of these? On x86, the one-byte NOP 0x90 is the `xchg ax,ax` special case of the one-byte `xchg`-with-ax short forms, 0x90..0x97. – Peter Cordes May 05 '18 at 11:41
  • 1
    @PeterCordes No the `NOP` opcode is `0x00`, all the others are unique. [Here's a list](http://www.pastraiser.com/cpu/gameboy/gameboy_opcodes.html) – Spooze May 05 '18 at 11:48
  • Huh, then the weird thing is that they "wasted" `00` on NOP, unless these `ld` opcodes have any side effects like setting flags. – Peter Cordes May 05 '18 at 11:54
  • 1
    @PeterCordes they don't have any side effect, it's really wasted opcode for `nop`. Actually makes me even wonder why they didn't treat those `same,same` as some kind of prefix bytes, like they have for regs `ix/iy` and bit instructions, whether the transistor logic catching those prefixes chouldn't have been part of `LD` ... but then again, I don't understand almost anything about chip circuitry design, so I may be struggling with something completely obvious from the point of view of hand design CPU. (GameBoy doesn't have `ix/iy` regs IIRC, they are on original Z80 only - to not confuse OP) – Ped7g May 05 '18 at 12:14
  • @Ped7g: Maybe the Z80 designers didn't have any great ideas that would fit their transistor budget for what to do with more opcodes. Extra prefixes would make the decoder more complex, but you'd think that doing something with `00` would have made sense. – Peter Cordes May 05 '18 at 12:20
  • 2
    To clarify a little, on the eZ80, which is backwards compatible, those instructions are actually used for a special purpose (basically to signal when an instruction should be used in a special mode from the rest of the routine). – Zeda May 05 '18 at 12:27
  • @PeterCordes I mean there already are prefixes (CB, DD, ED I think and one more, but I'm writing it from head, so not sure), so I wonder whether they couldn't have been part of those `LD` ones instead, and make the whole set more orthogonal, or how to say it, there're some other instructions lacking in variability pretty badly, especially once you got used to x86 variants. (although I still miss `RET cc` and `CALL cc` on x86 :) ) – Ped7g May 05 '18 at 12:28
  • 4
    @PeterCordes Having `00` be a `NOP` is important though: In some machines like the ZX80 the video logic uses the CPU as address generator by just forcing the data bus low to make the CPU execute `NOP`s. – Stefan Paul Noack Oct 01 '18 at 12:46

2 Answers2

15

They simplify the decoding unit, if you will check

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

vs

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

vs

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

You can notice, that the bottom 3 bits are reserved for source register (values 0-7 going B,C,D,E,H,L,(HL),A), 3 bits next to them are target register, again having the same 0-7 meaning (thus 0 vs 0 creates LD B,B), and the top two bits 01 select the LD, not sure from the quick glance if I deciphered it perfectly.

One would also expect then 76 to be LD (HL),(HL), which makes even less sense than LD A,A, so there's special logic to catch that one and do HALT instead.

So it's about simplicity of instruction decoder, using the same bit patterns to select source/target registers, and about not adding more transistors to catch the same,same situations, except the (HL),(HL) (which maybe will internally fail on both source and target requiring memory access, so maybe the extra "logic" is fairly simple in the HW design.

Keep in mind the early CPUs were often hand-designed and the amount of total transistors had to be kept low both to fit on the chip, and to be manageable to draw the circuitry by hand and verify its correctness.

EDIT: The Z80 has about 8500 transistors, you may want to check: https://en.wikipedia.org/wiki/Transistor_count and https://en.wikipedia.org/wiki/Zilog_Z80 ... and GameBoy has a bit modified Z80, but the amount of total transistors will be very close-ish to the original value, although I didn't search for exact value, and I'm not sure how far into the future the Nintendo was extending it, maybe they could afford even going for something like 20-50k already, but I doubt it.


Addendum: lately I have read about the Russian Sinclair ZX Spectrum clones, which were heavily modified machines, adding extra power, memory and capabilities... And some of them are using these ld same,same opcodes to control DMA transfers, so on these machines code using them as nop would probably fail to execute properly. This is not GameBoy related, but in case you have binary targetting one of the "Sprinter" or similar Russian ZX clones, and you find one of these in disassembly, don't consider them automatically nop, they may be part of effective code actually doing something (most probably with DMA).

Ped7g
  • 16,236
  • 3
  • 26
  • 63
5

These curious NOP instructions go all the way back to the original ancestor processor the Intel 8008. In that chip, they were merely an result of the implementation of the register move instruction. Allowing MOV A,A etc simplified the instruction decoder and saved silicon space.

From the 8080 through to the Z80 (and beyond), these became required to maintain backwards compatibility. They even survived into the x86 world in the form

MOV AL,AL etc.

So most modern desktop machines still support these odd instructions.

Note: I used Intel mnemonics when describing Intel machines. Be assured that these assemble down to the same binary code as the Zilog mnemonics.

Peter Camilleri
  • 1,882
  • 15
  • 17