Game Boy:半进位标志和 16 位指令(尤其是操作码 0xE8) [英] Game Boy: Half-carry flag and 16-bit instructions (especially opcode 0xE8)

查看:25
本文介绍了Game Boy:半进位标志和 16 位指令(尤其是操作码 0xE8)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Like so many others, I am writing a Game Boy emulator and I have a couple of questions regarding the instruction 0xE8 (ADD SP, n with an 8-bit immediate).

It is claimed here that in 16-bit instructions the half-carry flag is set if a carry occurs from bit 7 to bit 8, whereas here it is said that the half-carry flag indicates carry from bit 11 to bit 12. In this Reddit thread there seems to be a bit of confusion regarding the issue, and the (notoriously flawed, I hear) Game Boy CPU manual doesn't seem to have anything useful to say either.

My questions are the following:

  1. How does the half-carry flag behave in opcode 0xE8?
  2. How is the opcode 0xE8 implemented in the physical hardware?
  3. Which is right, that half-carry occurs from bit 7 to bit 8 or that half-carry occurs from bit 11 to bit 12 (in the case of 16-bit instructions)?

解决方案

The SM83 CPU core used in Game Boy almost certainly has a 8-bit ALU, which means 16-bit ALU operations are actually composed of two 8-bit operations. Like a normal Z80 CPU, it also has a dedicated 16-bit increment/decrement/load unit, which can handle certain 16-bit operations quickly but can't update the flags. Basically:

  • if flags are updated, a 16-bit operation definitely involves the ALU, so it actually uses two 8-bit ALU operations under the hood
  • if flags are not updated, and the 16-bit operation is just +1 / -1 / load, it's done with the 16-bit incrementer unit

So, whenever you're dealing with flags, try to think in terms of 8-bit operations (low byte first, then the high byte) if you want to reason about the operation.

  1. How does the half-carry flag behave in opcode 0xE8?

As pointed out in the other answer, H is set when there's a carry from bit 3. (And C is set when there's a carry from bit 7).

Here's an interesting thought exercise: if SP=$FFFF and you execute ADD SP, -1, you get SP=$FFFE and both H and C are set. Can you understand why?

Due to how signed numbers work, the low byte operation is in this case basically just a normal addition. -1 = $FF, so it's calculating $FF+ $FF.

Hint above ↑

  1. How is the opcode 0xE8 implemented in the physical hardware?

We don't yet have a full understanding of it at the lowest possible level, but I know that there are two 8-bit operations. With my Game Boy testbench system I've confirmed that there's first an ALU operation that updates the flags (H, C) but not SP, then some other operation, and finally SP is updated atomically in one go. This suggests that ADD SP, e might actually calculate the result into some temporary register (for example, a real Z80 has an invisible WZ temporary register for some ALU operations) in two separate 8-bit operations, and then load SP from it.

I think ADD HL, BC is a bit more interesting example...with my testbench I've confirmed that it updates L first and then H, and flags are updated twice. This means that it literally executes something like

ADD L, C
ADC H, B

The latter 8-bit operation updates the flags, so we never see the resulting flags of ADD L, C. But the half-carry flag might be temporarily set if there's a carry from L bit 3!

  1. Which is right, that half-carry occurs from bit 7 to bit 8 or that half-carry occurs from bit 11 to bit 12 (in the case of 16-bit instructions)?

It depends on the instruction, but the flags are always updated based on the same bit positions if you think in terms of 8-bit values...it just varies whether we're talking about the high or low byte of the 16-bit value. Bit 11 is just bit 3 of the high byte.

  • ADD SP, e: H from bit 3, C from bit 7 (flags from low byte op)
  • LD HL, SP+e: H from bit 3, C from bit 7 (flags from low byte op)
  • ADD HL, rr: H from bit 11, C from bit 15 (flags from high byte op)
  • INC rr: no flag updates (executed by the 16-bit inc/dec unit)
  • DEC rr: no flag updates (executed by the 16-bit inc/dec unit)

这篇关于Game Boy:半进位标志和 16 位指令(尤其是操作码 0xE8)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆