Z80上的溢出和进位标志

时间:2011-11-07 09:16:25

标签: math assembly z80

我已经完成了在我的Z80核心上实现ADD A,r组操作码。我对我认为已经钉好的进位和溢出标志有点困惑,但我想把它放到社区检查我是对的。

基本上,从我所看到的情况来看,Z80中的ALU并不关心有符号/无符号运算,它只是添加了位。这意味着如果将两个8位值相加并由于它们的相加而产生9位值,则将设置进位标志。这包括添加两个负二的补码数,例如-20(11101100)和-40(11011000),因为虽然结果是-60(11000100),但结果实际上是9位值1 1100 0100这肯定意味着如果添加两个负2的补码值,即使没有溢出条件,也会始终设置进位标志 - 我是对的吗?

其次,我决定检测此指令中的溢出,我会对两个操作数的第7位进行异或,如果结果是10000000,那么肯定没有溢出 - 如果结果是00000000则可能存在因为符号是相同的溢出,因此我将XOR的第7位与任一操作数的第7位进行异或,如果结果为10000000,则发生溢出并设置P / V溢出旗。我也在这儿吗?

对于这样一个令人费解的问题,我很抱歉,我确定我是对的,但我需要先知道,然后再根据这个逻辑继续执行更多的指令。非常感谢。

2 个答案:

答案 0 :(得分:32)

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

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

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

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

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

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

溢出标志=进位标志XOR从第6位进入第7位。

我和你计算溢出标志的方法都是正确的。实际上,两者都在Z80 CPU User's Manual“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位的方法,您还可以免费获得所需的half-carry标志值(从第3位到第4位)对于DAA指令。

编辑:我已经借助借阅(SBC / SBB指令)添加了减法功能,并为其提供了结果。

答案 1 :(得分:5)

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

  • 签名始终设置为结果的第7位
  • 如果结果为0x00 ,则设置
  • 当操作数的右半字节总和溢出时设置半进位
  • 溢出在两个操作数均为正数且有符号和为负数或两个操作数均为负数且有符号总和为正数时设置
  • 添加/子重置
  • 如果无符号和溢出0xFF ,则设置
  • 进位