Z80 上的溢出和进位标志
我已经开始在我的 Z80 核心上实现 ADD A,r 操作码集。我对进位和溢出标志有点困惑,我认为我已经解决了这些问题,但我想将其提交给社区以检查我是否正确。
基本上,据我所知,Z80 中的 ALU 不关心有符号/无符号操作,它只是添加位。这意味着如果两个 8 位值相加在一起并产生 9 位值作为其相加结果,则将设置进位标志。这包括将两个负的补码数相加,例如 -20 (11101100) 和 -40 (11011000),虽然结果是 -60 (11000100),但结果实际上是一个 9 位值 1 1100 0100。这肯定意味着如果添加两个负的二进制补码值,即使没有溢出条件,进位标志也将始终被设置 - 我是对的吗?
其次,我决定要检测该指令中的溢出,我将对两个操作数的第 7 位进行异或,如果结果是 10000000,那么肯定没有溢出 - 如果结果是 00000000,那么可能会发生溢出,如下所示符号是相同的,因此我会将加法结果的第 7 位与任一操作数的第 7 位进行异或,如果结果是 10000000,则发生溢出,我设置了 P/V 溢出标志。我也在这里吗?
很抱歉提出这样一个复杂的问题,我很确定我是对的,但在我继续基于这个逻辑的无数指令之前我需要知道。非常感谢。
I have gotten round to implementing the ADD A,r set of opcodes on my Z80 core. I had a bit of confusion about the carry and overflow flags which I think I've nailed, but I wanted to put it to the community to check that I'm right.
Basically, from what I can see, the ALU in the Z80 doesn't care about signed/unsigned operations, it just adds bits. This means that if two 8-bit values are added together and cause a 9-bit value as a result of their addition, the carry flag will be set. This includes adding two negative two's complement numbers, for example -20 (11101100) and -40 (11011000), as although the result is -60 (11000100), the result is actually a 9-bit value 1 1100 0100. This surely means if adding two negative two's complement values, the carry flag will always be set, even when there is no overflow condition - am I right?
Secondly, I decided that to detect an overflow in this instruction, I would XOR bit 7 of both operands, and if the result was 10000000, then there is definitely no overflow - if the result of this is 00000000 then there could be an overflow as the signs are the same, and I would therefore XOR bit 7 of the result of the addition with bit 7 of either operand, and if the result of this is 10000000 then an overflow has occurred and I set the P/V overflow flag. Am I right here also?
Sorry for such a convoluted question, I'm pretty sure I'm right but I need to know before I carry on with countless more instructions based on this logic. Many thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
结果的位是从无符号整数的截断和中获得的。 add 指令不关心这里的符号,也不关心您自己对整数有符号或无符号的解释。它只是添加,就好像数字没有签名一样。
进位标志(或减法中的借位)是 8 位无符号整数相加后不存在的第 9 位。实际上,该标志表示无符号整数的加法/减法的上溢/下溢。同样,add 根本不关心这里的符号,它只是相加,就好像数字没有符号一样。
添加两个负 2 的补码将导致进位标志设置为 1,正确。
溢出标志显示有符号整数的加法/减法是否存在上溢/下溢。为了设置溢出标志,指令将数字视为有符号(就像将它们视为进位标志和结果的 8 位无符号一样)。
设置溢出标志背后的想法很简单。假设您将 8 位有符号整数符号扩展为 9 位,也就是说,只需将第 7 位复制到额外的第 8 位。如果这些 9 位有符号整数的 9 位和/差在第 7 位和第 8 位具有不同的值,则会发生上溢/下溢,这意味着加法/减法已经丢失了结果在第 7 位的符号并将其用于结果的大小,或者换句话说,8 位无法容纳符号位和如此大的大小。
现在,当且仅当进入位 7 的进位和进入位 8 的进位(= 位 7 的进位)不同时,结果的位 7 可以与虚数符号位 8 不同。这是因为我们从具有位 7 = 位 8 的加数开始,并且只有不同的进位才能以不同的方式影响结果。
所以溢出标志 = 进位标志 XOR 从位 6 进位到位 7。
我和你计算溢出标志的方法都是正确的。事实上,两者都在Z80 CPU 用户手册中的“Z80 Status”部分中进行了描述指示标志”。
以下是如何用 C 语言模拟大多数 ADC 指令,您无法直接访问 CPU 的标志,也无法充分利用模拟 CPU 的 ADC 指令:
输出:
您可以更改
#if 0
改为#if 1
以使用基于符号比较的方法进行溢出计算。结果是一样的。乍一看,有点令人惊讶的是基于符号的方法也处理进位。请注意,通过使用我计算位 0 到位 7 中所有进位的方法,您还可以免费获得
half-carry
标志的值(从位 3 进位到位 4)这是DAA
指令所需要的。编辑:我添加了一个带借位的减法函数(SBC/SBB 指令)及其结果。
The bits of the result are obtained from the truncated sum of unsigned integers. The add instruction doesn't care about the sign here nor does it care about your own interpretation of the integers as signed or unsigned. It just adds as if the numbers were unsigned.
The carry flag (or borrow in case of subtraction) is that non-existent 9th bit from the addition of the 8-bit unsigned integers. Effectively, this flag signifies an overflow/underflow for add/sub of unsigned integers. Again, add doesn't care about the signs here at all, it just adds as if the numbers were unsigned.
Adding two negative 2's complement numbers will result in setting of the carry flag to 1, correct.
The overflow flag shows whether or not there's been an overflow/underflow for add/sub of signed integers. To set the overflow flag the instruction treats the numbers as signed (just like it treats them as unsigned for the carry flag and the 8 bits of the result).
The idea behind setting the overflow flag is simple. Suppose you sign-extend your 8-bit signed integers to 9 bits, that is, just copy the 7th bit to an extra, 8th bit. An overflow/underflow will occur if the 9-bit sum/difference of these 9-bit signed integers has different values in bits 7 and 8, meaning that the addition/subtraction has lost the result's sign in the 7th bit and used it for the result's magnitude, or, in other words, the 8 bits can't accommodate the sign bit and such a large magnitude.
Now, bit 7 of the result can differ from the imaginary sign bit 8 if and only if the carry into bit 7 and the carry into bit 8 (=carry out of bit 7) are different. That's because we start with the addends having bit 7=bit 8 and only different carry-ins into them can affect them in the result in different ways.
So overflow flag = carry-out flag XOR carry from bit 6 into bit 7.
Both my and your ways of calculating the overflow flag are correct. In fact, both are described in the Z80 CPU User's Manual in section "Z80 Status Indicator Flags".
Here's how you can emulate most of the ADC instruction in C, where you don't have direct access to the CPU's flags and can't take full advantage of the emulating CPU's ADC instruction:
Output:
You can change
#if 0
to#if 1
to use the sign-comparison-based method for overflow calculation. The result will be the same. At first glance it's a bit surprising that the sign-based method takes care of the carry-in too.Please note that by using my method in which I calculate all carry-ins into bits 0 through 7, you also get for free the value of the
half-carry
flag (carry from bit 3 to bit 4) that's needed for theDAA
instruction.EDIT: I've added a function for subtraction with borrow (SBC/SBB instruction) and results for it.
另一种看待这个问题的方式可能更容易理解。执行求和时:
Another way to see this which is maybe easier to understand. When performing a sum: