7

I'm working on implementing the instructions of the z80 chip inside a gameboy for an emulator. I'm starting with the instructions in the boot rom that sets everything up.

I've implemented the first 3 instructions but the 4th one is throwing me for a loop with it's assembly notation and what I'm seeing in the opcode decoding chart I'm referencing.

The instruction, according to that wiki's disassembled code, is:

LD (HL-), A

If it were LD HL, A then I'd know that means "load register A's value in HL" (I know it's not valid because A is a byte while HL is 2 bytes, but I'm mostly talking about the notation). If it were LD (HL), A then, if I'm correct, that would mean "load register A's value into the memory address at the location stored in HL." I'm have no idea what the - of (HL-) means.

With that confusion, I decided to try working backwards. Location $0007 in the boot rom contains the single byte of 0x32 that is the instruction. 0x32 = 0b00110010 breaks down to x = 00, y = 110 (p = 11, q = 0), and z = 010 with no prefix, which the opcode chart indicates means LD (nn), A which doesn't contain HL at all and from the looks of it, there's not 2 immediate bytes after the instruction in the boot rom. This seems odd because I feel I can decode using this site pretty accurately. Is the site wrong?

I'm wrong about something somewhere but I'm not sure what. How do I reconcile these two observations and what's the right way to move forward?

EDIT: According to this site, LD (HL-), A means "load A into the memory address that HL points to, then decrement HL" which makes sense with what the wiki describes this program does. A was just cleared in the previous XOR A instruction and then it'll iterate through VRAM setting all of it to the value of zero. Now my concern is that I'm reading the instruction decoding site incorrectly as I don't see anything about decrementing a register after use.

  • Just for clear the Z80 mnemonics: - HL means "register pair HL", - (HL) means "memory cell addressed by the HL pair". – Martin Maly Jun 8 at 16:21
17

I'm working on implementing the instructions of the z80 chip inside a gameboy for an emulator.

Well, I guess that's the most important point here:

The Gameboy doesn't feature a Z80, but an independent 8080 descendant.

Using a Z80 opcode table will not get you anywhere.

It's LR35902 CPU (*1) is, like the Z80, based on the 8080 with some extensions. The development of the LR35902 is independent of the Z80. The reason it gets often confused with the Z80 is that it's Assembler syntax and mnemonics have been changed from 8080 much the same way it was done by Zilog. Most notable the use of LD* for all transfers, which makes many 8080 instructions look exactly like on the Z80.

The instruction, according to that wiki's disassembled code, is LD (HL-), A [...] Location $0007 in the boot rom contains the single byte of 0x32 [...] means LD (nn), A

(*2)

True, if this would be an 8080 or Z80. Here it's a 3 byte instruction with opcode 32h and two bytes holding an absolute (16 bit) address. In 8080 Assembler this would be a STA addr meaning store A at the absolute address (*3). In Z80 lingo it's LD (xx),A. Same opcode, same encoding, same operation.

The LR35902 replaced this instruction by a single byte instruction storing the content of A at a location pointed to by HL and decrement HL afterwards. So the opcode 32h has a different meaning and different length (implied instead of explicite address)

In LR35902 Assembly this can be written as:

  • LD (HLD),A
  • LD (HL-),A
  • LDD (HL),A

The listing you're referring to uses the second way.

I'm wrong about something somewhere but I'm not sure what. How do I reconcile these two observations and what's the right way to move forward?

You're perfectly right, but using the wrong opcode table.

It may be helpful to cross reference to (unofficial) Game Boy CPU manual. It describes quite well most workings (*4) the only thing it misses is a good opcode table, but as so often Pastiser offers a great one.


*1 - As tobiasvl points out, it's worth to keep in mind that LR35902 names the whole System-on-a-Chip. It is most likely based on Sharp's SM83xx family, thus the 'real' CPU 'part' would be a SM83 core. See as well the 1996 data book with the instruction set starting at p.182. I still keep using LR35902 thruout this as it's the common found reference.

*2 - BTW, try to not use spaces after a comma. This is Assembler, not C. (White) Spaces do have a meaning in Assembly. While this may be fine with the assembler you're using, it's not portable at all.

*3 - As mentioned, the 8080 used different mnemonics for various transfers while the Z80 unified this.

*4 - That is, once you get used to its rather unorthodox structure - it's less of a reference than a book one needs to be read like a novel.

| improve this answer | |
  • 1
    I'd always heard it was a MODIFIED z80 but hadn't found any details about what was modified. You're completely right, the opcode decoding page I was using was strictly z80, BUT there's a gameboy version that properly shows 0x32 as LD (HL-), A! – Corey Ogburn Jun 8 at 0:00
  • 1
    @CoreyOgburn as so often there are many ways to see it. A modified 8080, or a Z80 striped of next to all extensions the Z80 had over the 8080 and modified as well. To me the later feels quite mind boggling, so I go with the simple version :) Go with the links I've given. Both don'T speculate but take the LR35902 as it is. – Raffzahn Jun 8 at 0:13
  • 1
    Just a note: LR35902 is the SoC, the CPU is (in all likelihood) a Sharp SM83. – tobiasvl Jun 8 at 12:57
  • Also note that Pastraiser's opcode table for the GB contains some cycle inaccuracies, and some other potentially confusing things (like listing $E9 as JP (HL) instead of JP HL). I recommend this one which is open source on GitHub and actively developed by the community gbdev.io/gb-opcodes/optables – tobiasvl Jun 8 at 13:00
  • @tobiasvl True, then again, I rather stay with the original than some copy. Most important, tables fiddling with representation are a bad service. Leaving off the parentheses is simply wrong, as they indicate a memory reference in Z80 assembly. While it may seam strange, Zilog did write JMP (HL) for E9h, as well did Sharp (see data book p.187). Last but not least, I can't see any reference of the original developer open sourcing it. Taking a table from a website changing a tiny bit is of no good. – Raffzahn Jun 8 at 13:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.