24

Z80 コアにオペコードの ADD A,r セットを実装する準備が整いました。キャリー フラグとオーバーフロー フラグについて少し混乱がありましたが、それが正しいことを確認するためにコミュニティに投稿したかったのです。

基本的に、私が見る限り、Z80 の ALU は符号付き/符号なし操作を気にせず、ビットを追加するだけです。これは、2 つの 8 ビット値が加算され、加算の結果が 9 ビット値になる場合、キャリー フラグが設定されることを意味します。これには、-20 (11101100) と -40 (11011000) などの 2 つの負の 2 の補数を加算することが含まれます。結果は -60 (11000100) ですが、結果は実際には 9 ビット値 1 1100 0100 になります。 2 つの負の 2 の補数値を加算すると、オーバーフロー条件がない場合でもキャリー フラグが常に設定されます。

次に、この命令のオーバーフローを検出するために、両方のオペランドのビット 7 を XOR し、結果が 10000000 の場合、オーバーフローは絶対にありません。結果が 00000000 の場合、次のようにオーバーフローが発生する可能性があります。符号は同じなので、どちらかのオペランドのビット 7 との加算結果のビット 7 を XOR します。この結果が 10000000 の場合、オーバーフローが発生し、P/V オーバーフロー フラグを設定します。私もここにいるの?

このような複雑な質問で申し訳ありませんが、私は正しいと確信していますが、このロジックに基づいて無数の指示を続ける前に知っておく必要があります. どうもありがとう。

4

2 に答える 2

37

結果のビットは、符号なし整数の切り捨てられた合計から取得されます。add 命令は、ここでは符号を気にしません。また、整数を符号付きまたは符号なしとして独自に解釈することも気にしません。数字が符号なしであるかのように追加するだけです。

キャリー フラグ (減算の場合はボロー) は、8 ビットの符号なし整数を加算した、存在しない 9 番目のビットです。事実上、このフラグは、符号なし整数の加算/減算のオーバーフロー/アンダーフローを示します。繰り返しますが、add は符号をまったく気にせず、数値が符号なしであるかのように加算します。

2 つの負の 2 の補数を加算すると、キャリー フラグが 1 に設定されます。正しいです。

オーバーフロー フラグは、符号付き整数の加算/減算でオーバーフロー/アンダーフローが発生したかどうかを示します。オーバーフロー フラグを設定するために、命令は数値を符号付きとして扱います (キャリー フラグと結果の 8 ビットに対して符号なしとして扱うのと同じように)。

オーバーフロー フラグの設定の背後にある考え方は単純です。8 ビットの符号付き整数を 9 ビットに符号拡張するとします。つまり、7 番目のビットを余分な 8 番目のビットにコピーするだけです。これらの 9 ビット符号付き整数の 9 ビット和/差のビット 7 と 8 の値が異なる場合、オーバーフロー/アンダーフローが発生します。これは、加算/減算によって 7 番目のビットで結果の符号が失われ、それが結果の大きさ、つまり、8 ビットでは符号ビットとそのような大きな大きさに対応できません。

ここで、ビット 7 へのキャリーとビット 8 へのキャリー (= ビット 7 のキャリー アウト) が異なる場合にのみ、結果のビット 7 が虚数符号のビット 8 と異なる場合があります。これは、ビット 7=ビット 8 を持つ加数から開始し、それらへの異なるキャリーインのみが異なる方法で結果に影響を与える可能性があるためです。

したがって、オーバーフロー フラグ = キャリー アウト フラグ ビット 6 からビット 7 への XOR キャリー。

オーバーフローフラグを計算する私の方法とあなたの方法の両方が正しいです。実際、両方ともZ80 CPU ユーザーズ マニュアルのセクション「Z80 ステータス インジケータ フラグ」に記載されています。

CPU のフラグに直接アクセスできず、エミュレートする CPU の ADC 命令を最大限に活用できない C でほとんどの 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 the same
  {
    // 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 命令) とその結果を使用して減算する関数を追加しました。

于 2011-11-07T14:02:16.190 に答える