7

The Game Boy game "Tetris" leaves a transmission interval of about a millisecond between bytes sent over the serial link, as suggested by the official Game Boy Programming Manual, to give the other device the time to keep up with the data if it were to have an interrupt. It does that by simply busy looping 240 times, every iteration of that loop takes 4 cycles for a total of 960 cycles, which is close enough to a millisecond. The relevant code looks like this

    ld b, 240
.loop
    ld b, b
    dec b
    jr nz, .loop

My question is, why did they use an LD B, B instruction, and not a proper NOP? Functionally, they're identical, they take the same time and they both set no flags. Could this be a remnant from development, with the instruction having a trap or debug function on development kits?

4
  • 4
    “Just to confuse the Russians” ;-)
    – StarCat
    Apr 15, 2021 at 20:24
  • 1
    Just a guess, so just a comment: Perhaps doing it this way is to prevent any later automated optimization from messing up the code. NOP by itself would seem to be "get rid of it - oh, must be for timing, leave it in place", but by operating on the b register, even with a self-load, you avoid an optimization of "loop dec, jr nz" being replaced with just "ld b,0" since an operation on b inside the loop means you can't just optimize the whole thing away. Apr 15, 2021 at 20:26
  • Not that it changes the question, but 4 cycles? Isn't it 4+4+12 cycles per iteration?
    – UncleBod
    Apr 15, 2021 at 20:41
  • 1
    @UncleBod You are correct, there are 16 clock cycles per iteration, but the programming manual uses the word cycles to refer to instruction cycles, which differ by a factor of 4. I think in Z80 language they are called T-cycles and M-cycles
    – Kasper
    Apr 16, 2021 at 13:42

1 Answer 1

11

My question is, why did they use an LD B, B instruction, and not a proper NOP?

LD B,B works like a NOP - at least as stated in the original 8080 manual (*1):

enter image description here

The original 8080 had 8 NOPs at 00xxx000 but only the first was defined as 'the nop'. In addition there were 7 instructions of loading a register with itself (*2). Effective NOPs, but not defined as such.

The GB CPU, as an 8080 descendant did (like the 8085 and Z80) redefine 7 of the NOPs as new instructions, but kept the self loading NOPs.

Could this be a remnant from development, with the instruction having a trap or debug function on development kits?

IMHO the most likely reason.

For example a way to distinguish 'wait' NOP from such inserted for other reasons. While this may be done on source level as well with macros, using a different encoding does as well allow to find them in binary. When doing low level debugging (*3), seeing a 40h instead of a 00h is attention raising like a Tag in HTML :))

Different encoding highlights them not only to the human eye, but makes them as well visible for ICE debugers, allowing to stop at such opcodes without falling over any other NOP.

There are many positive use cases, why it was chosen in detail might be shrouded in history.


*1 - The Game Boy CPU is, despite the assembler syntax, a direct 8080 offspring.

*2 - The 8th, LD (HL),(HL), was already at with the 8080 redefined as HALT

*3 - Even the rather advanced development systems Nintendo used were less comfortable than some modern products. Not to mention situations when all visible were bare bytes.

1
  • Some assemblers use strange encodings (e.g., so they can trace who's using their assembler), so there's at least some chance that in the original source code, it was actually written as "NOP". Apr 16, 2021 at 18:53

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .