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溢出标志。 我也在这里吗?

对不起,这样一个复杂的问题,我很确定我是对的,但我需要知道之前,我继续无数更多的指令基于这个逻辑。 非常感谢。

结果的位是从无符号整数的截取和得到的。 加法指令并不关心这里的符号,也不关心你自己对整数的解释,如有符号或无符号。 它只是添加好像数字是无符号的。

进位标志(或减法情况下的借位)是8位无符号整数中不存在的第9位。 实际上,该标志表示无符号整数的add / sub溢出/下溢。 同样,添加不关心这里的标志,它只是增加了,就好像这些数字是无符号的。

增加两个负2的补码数将导致进位标志设置为1,是正确的。

溢出标志显示有符号整数的add / sub是否有溢出/下溢。 为了设置溢出标志,指令将数字视为有符号的(就像它将它们视为进位标志和结果的8位无符号一样)。

设置溢出标志的想法很简单。 假设您将8位有符号整数签名扩展为9位,即将第7位复制到第8位。 如果这些9位有符号整数的9位和/差在位7和位8中有不同的值,就会发生溢出/下溢,这意味着加/减在第7位丢失了结果的符号,并将其用于结果的大小,或者换句话说,8位不能容纳符号位和如此大的幅度。

现在,结果的第7位可以和第8位的虚符号有所不同,当且仅当进位到第7位和进位第8位(=第7位的进位)不同。 这是因为我们从位7 =位8的加数开始,只有不同的进位可以以不同的方式影响结果。

所以溢出标志=进位标志XOR从位6进位到位7。

我和你的计算溢出标志的方法都是正确的。 实际上,在“ Z80 CPU用户手册 ”的“Z80状态指示标志”一节中都有介绍。

下面介绍如何模拟C语言中的大部分ADC指令,其中不能直接访问CPU的标志,也不能充分利用仿真CPU的ADC指令:

#include <stdio.h> #include <limits.h> #if CHAR_BIT != 8 #error char expected to have exactly 8 bits. #endif typedef unsigned char uint8; typedef signed char int8; #define FLAGS_CY_SHIFT 0 #define FLAGS_OV_SHIFT 1 #define FLAGS_CY_MASK (1 << FLAGS_CY_SHIFT) #define FLAGS_OV_MASK (1 << FLAGS_OV_SHIFT) void Adc(uint8* acc, uint8 b, uint8* flags) { uint8 a = *acc; uint8 carryIns; uint8 carryOut; // Calculate the carry-out depending on the carry-in and addends. // // carry-in = 0: carry-out = 1 IFF (a + b > 0xFF) or, // equivalently, but avoiding overflow in C: (a > 0xFF - b). // // carry-in = 1: carry-out = 1 IFF (a + b + 1 > 0xFF) or, // equivalently, (a + b >= 0xFF) or, // equivalently, but avoiding overflow in C: (a >= 0xFF - b). // // Also calculate the sum bits. if (*flags & FLAGS_CY_MASK) { carryOut = (a >= 0xFF - b); *acc = a + b + 1; } else { carryOut = (a > 0xFF - b); *acc = a + b; } #if 0 // Calculate the overflow by sign comparison. carryIns = ((a ^ b) ^ 0x80) & 0x80; if (carryIns) // if addend signs are different { // overflow if the sum sign differs from the sign of either of addends carryIns = ((*acc ^ a) & 0x80) != 0; } #else // Calculate all carry-ins. // Remembering that each bit of the sum = // addend a's bit XOR addend b's bit XOR carry-in, // we can work out all carry-ins from a, b and their sum. carryIns = *acc ^ a ^ b; // Calculate the overflow using the carry-out and // most significant carry-in. carryIns = (carryIns >> 7) ^ carryOut; #endif // Update flags. *flags &= ~(FLAGS_CY_MASK | FLAGS_OV_MASK); *flags |= (carryOut << FLAGS_CY_SHIFT) | (carryIns << FLAGS_OV_SHIFT); } void Sbb(uint8* acc, uint8 b, uint8* flags) { // a - b - c = a + ~b + 1 - c = a + ~b + !c *flags ^= FLAGS_CY_MASK; Adc(acc, ~b, flags); *flags ^= FLAGS_CY_MASK; } const uint8 testData[] = { 0, 1, 0x7F, 0x80, 0x81, 0xFF }; int main(void) { unsigned aidx, bidx, c; printf("ADC:\n"); for (c = 0; c <= 1; c++) for (aidx = 0; aidx < sizeof(testData)/sizeof(testData[0]); aidx++) for (bidx = 0; bidx < sizeof(testData)/sizeof(testData[0]); bidx++) { uint8 a = testData[aidx]; uint8 b = testData[bidx]; uint8 flags = c << FLAGS_CY_SHIFT; printf("%3d(%4d) + %3d(%4d) + %u = ", a, (int8)a, b, (int8)b, c); Adc(&a, b, &flags); printf("%3d(%4d) CY=%d OV=%d\n", a, (int8)a, (flags & FLAGS_CY_MASK) != 0, (flags & FLAGS_OV_MASK) != 0); } printf("SBB:\n"); for (c = 0; c <= 1; c++) for (aidx = 0; aidx < sizeof(testData)/sizeof(testData[0]); aidx++) for (bidx = 0; bidx < sizeof(testData)/sizeof(testData[0]); bidx++) { uint8 a = testData[aidx]; uint8 b = testData[bidx]; uint8 flags = c << FLAGS_CY_SHIFT; printf("%3d(%4d) - %3d(%4d) - %u = ", a, (int8)a, b, (int8)b, c); Sbb(&a, b, &flags); printf("%3d(%4d) CY=%d OV=%d\n", a, (int8)a, (flags & FLAGS_CY_MASK) != 0, (flags & FLAGS_OV_MASK) != 0); } return 0; } 

输出:

 ADC: 0( 0) + 0( 0) + 0 = 0( 0) CY=0 OV=0 0( 0) + 1( 1) + 0 = 1( 1) CY=0 OV=0 0( 0) + 127( 127) + 0 = 127( 127) CY=0 OV=0 0( 0) + 128(-128) + 0 = 128(-128) CY=0 OV=0 0( 0) + 129(-127) + 0 = 129(-127) CY=0 OV=0 0( 0) + 255( -1) + 0 = 255( -1) CY=0 OV=0 1( 1) + 0( 0) + 0 = 1( 1) CY=0 OV=0 1( 1) + 1( 1) + 0 = 2( 2) CY=0 OV=0 1( 1) + 127( 127) + 0 = 128(-128) CY=0 OV=1 1( 1) + 128(-128) + 0 = 129(-127) CY=0 OV=0 1( 1) + 129(-127) + 0 = 130(-126) CY=0 OV=0 1( 1) + 255( -1) + 0 = 0( 0) CY=1 OV=0 127( 127) + 0( 0) + 0 = 127( 127) CY=0 OV=0 127( 127) + 1( 1) + 0 = 128(-128) CY=0 OV=1 127( 127) + 127( 127) + 0 = 254( -2) CY=0 OV=1 127( 127) + 128(-128) + 0 = 255( -1) CY=0 OV=0 127( 127) + 129(-127) + 0 = 0( 0) CY=1 OV=0 127( 127) + 255( -1) + 0 = 126( 126) CY=1 OV=0 128(-128) + 0( 0) + 0 = 128(-128) CY=0 OV=0 128(-128) + 1( 1) + 0 = 129(-127) CY=0 OV=0 128(-128) + 127( 127) + 0 = 255( -1) CY=0 OV=0 128(-128) + 128(-128) + 0 = 0( 0) CY=1 OV=1 128(-128) + 129(-127) + 0 = 1( 1) CY=1 OV=1 128(-128) + 255( -1) + 0 = 127( 127) CY=1 OV=1 129(-127) + 0( 0) + 0 = 129(-127) CY=0 OV=0 129(-127) + 1( 1) + 0 = 130(-126) CY=0 OV=0 129(-127) + 127( 127) + 0 = 0( 0) CY=1 OV=0 129(-127) + 128(-128) + 0 = 1( 1) CY=1 OV=1 129(-127) + 129(-127) + 0 = 2( 2) CY=1 OV=1 129(-127) + 255( -1) + 0 = 128(-128) CY=1 OV=0 255( -1) + 0( 0) + 0 = 255( -1) CY=0 OV=0 255( -1) + 1( 1) + 0 = 0( 0) CY=1 OV=0 255( -1) + 127( 127) + 0 = 126( 126) CY=1 OV=0 255( -1) + 128(-128) + 0 = 127( 127) CY=1 OV=1 255( -1) + 129(-127) + 0 = 128(-128) CY=1 OV=0 255( -1) + 255( -1) + 0 = 254( -2) CY=1 OV=0 0( 0) + 0( 0) + 1 = 1( 1) CY=0 OV=0 0( 0) + 1( 1) + 1 = 2( 2) CY=0 OV=0 0( 0) + 127( 127) + 1 = 128(-128) CY=0 OV=1 0( 0) + 128(-128) + 1 = 129(-127) CY=0 OV=0 0( 0) + 129(-127) + 1 = 130(-126) CY=0 OV=0 0( 0) + 255( -1) + 1 = 0( 0) CY=1 OV=0 1( 1) + 0( 0) + 1 = 2( 2) CY=0 OV=0 1( 1) + 1( 1) + 1 = 3( 3) CY=0 OV=0 1( 1) + 127( 127) + 1 = 129(-127) CY=0 OV=1 1( 1) + 128(-128) + 1 = 130(-126) CY=0 OV=0 1( 1) + 129(-127) + 1 = 131(-125) CY=0 OV=0 1( 1) + 255( -1) + 1 = 1( 1) CY=1 OV=0 127( 127) + 0( 0) + 1 = 128(-128) CY=0 OV=1 127( 127) + 1( 1) + 1 = 129(-127) CY=0 OV=1 127( 127) + 127( 127) + 1 = 255( -1) CY=0 OV=1 127( 127) + 128(-128) + 1 = 0( 0) CY=1 OV=0 127( 127) + 129(-127) + 1 = 1( 1) CY=1 OV=0 127( 127) + 255( -1) + 1 = 127( 127) CY=1 OV=0 128(-128) + 0( 0) + 1 = 129(-127) CY=0 OV=0 128(-128) + 1( 1) + 1 = 130(-126) CY=0 OV=0 128(-128) + 127( 127) + 1 = 0( 0) CY=1 OV=0 128(-128) + 128(-128) + 1 = 1( 1) CY=1 OV=1 128(-128) + 129(-127) + 1 = 2( 2) CY=1 OV=1 128(-128) + 255( -1) + 1 = 128(-128) CY=1 OV=0 129(-127) + 0( 0) + 1 = 130(-126) CY=0 OV=0 129(-127) + 1( 1) + 1 = 131(-125) CY=0 OV=0 129(-127) + 127( 127) + 1 = 1( 1) CY=1 OV=0 129(-127) + 128(-128) + 1 = 2( 2) CY=1 OV=1 129(-127) + 129(-127) + 1 = 3( 3) CY=1 OV=1 129(-127) + 255( -1) + 1 = 129(-127) CY=1 OV=0 255( -1) + 0( 0) + 1 = 0( 0) CY=1 OV=0 255( -1) + 1( 1) + 1 = 1( 1) CY=1 OV=0 255( -1) + 127( 127) + 1 = 127( 127) CY=1 OV=0 255( -1) + 128(-128) + 1 = 128(-128) CY=1 OV=0 255( -1) + 129(-127) + 1 = 129(-127) CY=1 OV=0 255( -1) + 255( -1) + 1 = 255( -1) CY=1 OV=0 SBB: 0( 0) - 0( 0) - 0 = 0( 0) CY=0 OV=0 0( 0) - 1( 1) - 0 = 255( -1) CY=1 OV=0 0( 0) - 127( 127) - 0 = 129(-127) CY=1 OV=0 0( 0) - 128(-128) - 0 = 128(-128) CY=1 OV=1 0( 0) - 129(-127) - 0 = 127( 127) CY=1 OV=0 0( 0) - 255( -1) - 0 = 1( 1) CY=1 OV=0 1( 1) - 0( 0) - 0 = 1( 1) CY=0 OV=0 1( 1) - 1( 1) - 0 = 0( 0) CY=0 OV=0 1( 1) - 127( 127) - 0 = 130(-126) CY=1 OV=0 1( 1) - 128(-128) - 0 = 129(-127) CY=1 OV=1 1( 1) - 129(-127) - 0 = 128(-128) CY=1 OV=1 1( 1) - 255( -1) - 0 = 2( 2) CY=1 OV=0 127( 127) - 0( 0) - 0 = 127( 127) CY=0 OV=0 127( 127) - 1( 1) - 0 = 126( 126) CY=0 OV=0 127( 127) - 127( 127) - 0 = 0( 0) CY=0 OV=0 127( 127) - 128(-128) - 0 = 255( -1) CY=1 OV=1 127( 127) - 129(-127) - 0 = 254( -2) CY=1 OV=1 127( 127) - 255( -1) - 0 = 128(-128) CY=1 OV=1 128(-128) - 0( 0) - 0 = 128(-128) CY=0 OV=0 128(-128) - 1( 1) - 0 = 127( 127) CY=0 OV=1 128(-128) - 127( 127) - 0 = 1( 1) CY=0 OV=1 128(-128) - 128(-128) - 0 = 0( 0) CY=0 OV=0 128(-128) - 129(-127) - 0 = 255( -1) CY=1 OV=0 128(-128) - 255( -1) - 0 = 129(-127) CY=1 OV=0 129(-127) - 0( 0) - 0 = 129(-127) CY=0 OV=0 129(-127) - 1( 1) - 0 = 128(-128) CY=0 OV=0 129(-127) - 127( 127) - 0 = 2( 2) CY=0 OV=1 129(-127) - 128(-128) - 0 = 1( 1) CY=0 OV=0 129(-127) - 129(-127) - 0 = 0( 0) CY=0 OV=0 129(-127) - 255( -1) - 0 = 130(-126) CY=1 OV=0 255( -1) - 0( 0) - 0 = 255( -1) CY=0 OV=0 255( -1) - 1( 1) - 0 = 254( -2) CY=0 OV=0 255( -1) - 127( 127) - 0 = 128(-128) CY=0 OV=0 255( -1) - 128(-128) - 0 = 127( 127) CY=0 OV=0 255( -1) - 129(-127) - 0 = 126( 126) CY=0 OV=0 255( -1) - 255( -1) - 0 = 0( 0) CY=0 OV=0 0( 0) - 0( 0) - 1 = 255( -1) CY=1 OV=0 0( 0) - 1( 1) - 1 = 254( -2) CY=1 OV=0 0( 0) - 127( 127) - 1 = 128(-128) CY=1 OV=0 0( 0) - 128(-128) - 1 = 127( 127) CY=1 OV=0 0( 0) - 129(-127) - 1 = 126( 126) CY=1 OV=0 0( 0) - 255( -1) - 1 = 0( 0) CY=1 OV=0 1( 1) - 0( 0) - 1 = 0( 0) CY=0 OV=0 1( 1) - 1( 1) - 1 = 255( -1) CY=1 OV=0 1( 1) - 127( 127) - 1 = 129(-127) CY=1 OV=0 1( 1) - 128(-128) - 1 = 128(-128) CY=1 OV=1 1( 1) - 129(-127) - 1 = 127( 127) CY=1 OV=0 1( 1) - 255( -1) - 1 = 1( 1) CY=1 OV=0 127( 127) - 0( 0) - 1 = 126( 126) CY=0 OV=0 127( 127) - 1( 1) - 1 = 125( 125) CY=0 OV=0 127( 127) - 127( 127) - 1 = 255( -1) CY=1 OV=0 127( 127) - 128(-128) - 1 = 254( -2) CY=1 OV=1 127( 127) - 129(-127) - 1 = 253( -3) CY=1 OV=1 127( 127) - 255( -1) - 1 = 127( 127) CY=1 OV=0 128(-128) - 0( 0) - 1 = 127( 127) CY=0 OV=1 128(-128) - 1( 1) - 1 = 126( 126) CY=0 OV=1 128(-128) - 127( 127) - 1 = 0( 0) CY=0 OV=1 128(-128) - 128(-128) - 1 = 255( -1) CY=1 OV=0 128(-128) - 129(-127) - 1 = 254( -2) CY=1 OV=0 128(-128) - 255( -1) - 1 = 128(-128) CY=1 OV=0 129(-127) - 0( 0) - 1 = 128(-128) CY=0 OV=0 129(-127) - 1( 1) - 1 = 127( 127) CY=0 OV=1 129(-127) - 127( 127) - 1 = 1( 1) CY=0 OV=1 129(-127) - 128(-128) - 1 = 0( 0) CY=0 OV=0 129(-127) - 129(-127) - 1 = 255( -1) CY=1 OV=0 129(-127) - 255( -1) - 1 = 129(-127) CY=1 OV=0 255( -1) - 0( 0) - 1 = 254( -2) CY=0 OV=0 255( -1) - 1( 1) - 1 = 253( -3) CY=0 OV=0 255( -1) - 127( 127) - 1 = 127( 127) CY=0 OV=1 255( -1) - 128(-128) - 1 = 126( 126) CY=0 OV=0 255( -1) - 129(-127) - 1 = 125( 125) CY=0 OV=0 255( -1) - 255( -1) - 1 = 255( -1) CY=1 OV=0 

您可以将#if 0更改为#if 1以使用基于符号比较的方法进行溢出计算。 结果将是一样的。 乍看之下,基于符号的方法也照顾到携带物,这有点令人惊讶。

请注意,通过使用我的方法,我计算所有的进位在0到7位,也可以获得DAA指令所需的half-carry标志(从第3位到第4位)的值。

编辑:我已经添加了借用(SBC / SBB指令)减法的function和结果。

另一种方法来看待这可能更容易理解。 执行总和时:

  • 符号总是设置为结果的第7位
  • 如果结果是0x00,则置
  • 当操作数的右半位总和溢出时, 半进位被设置
  • 如果两个操作数都是正数,且符号和为负,或者两个操作数都是负数,且符号和为正,则设置溢出
  • 添加/子被重置
  • 如果无符号和超过0xFF,进位置1