2011-11-07 88 views
21

我已經圍繞在我的Z80內核上實現ADD A,r一組操作碼。我對我認爲已經釘牢的攜帶和溢出標誌有一些疑惑,但我想把它帶到社區來檢查我是否正確。Z80上的溢出和進位標誌

基本上,從我所看到的,Z80中的ALU並不在乎簽名/未簽名的操作,它只是增加了一些位。這意味着如果將兩個8位值相加在一起並由於它們的相加而產生一個9位值,則進位標誌將被置位。這包括增加兩個負數的二進制補碼,例如-20(11101100)和-40(11011000),雖然結果是-60(11000100),結果實際上是9位值1 1100 0100.這肯定意味着如果增加兩個負二進制補碼值,即使沒有溢出條件,進位標誌也會一直置位 - 我說得對嗎?其次,我決定要在這個指令中檢測到溢出,我會將這兩個操作數的第7位異或,如果結果是10000000,那麼肯定沒有溢出 - 如果結果是00000000,那麼可能會有因爲符號是相同的,所以我會將加法結果的第7位與任一操作數的第7位異或,如果結果是10000000,則發生溢出,並且設置P/V溢出標誌。我也在這裏嗎?

對不起,我很確定我是對的,但在我繼續基於這個邏輯的無數指令之前,我需要知道。非常感謝。

回答

31

結果的位是從無符號整數的截斷和得到的。 add指令並不關心這裏的符號,也不關心你自己對整數的解釋是否有符號或無符號。它只是添加好像數字是無符號的。

進位標誌(或減法情況下的借位)是8位無符號整數相加後不存在的第9位。實際上,該標誌表示無符號整數的add/sub溢出/下溢。再一次,add並不關心這裏的符號,它只是增加了好像數字沒有簽名。

添加兩個負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 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使用溢出計算爲基礎的跡象比較方法。結果將是相同的。乍一看,基於符號的方法也會照顧到攜帶物,這有點令人驚訝。

請注意,用我的方法中,我通過7計算所有隨身攜帶的插件爲位0,您也可以免費獲得該half-carry標誌的值(從第3位進位至第4位)這是所需​​指令。

編輯:我已經添加了借用(SBC/SBB指令)減法函數和結果。

+0

這是一個完美的設置 - 非常感謝你:-)我知道我是沿着正確的線路。也感謝您的代碼示例。我實際上使用Java(因爲我的目標是完成一個完全跨平臺的主系統模擬器),儘管我可以理解足夠多的C以查看你在做什麼。對不起,如果我的問題看起來很簡單,那只是我在學習這個項目時不得不自學很多二進制數學,到目前爲止我似乎已經掌握了它:-) – PhilPotter1987

+0

感謝您的解釋,它確實很精確。我通過執行'halfCarryOut = carryIn?'來計算出halfcarry標誌。 ((a&0x0F)> = 0x0F - (a&0x0F)):((a&0x0F)> 0x0F - (a&0x0F)); halfCarryOut =((res^a^b)>> 4)^ halfCarryOut;',它應該是正確的。 – Jack

+1

@Jack如果你已經測試過它,它可以工作,好吧(我不會驗證它)。但是,如我在答覆結束時指出的那樣,它可以做得更簡單。使用#else和#endif之間的代碼變體。在'carryIns = * acc^a^b'之後''執行'halfCarryOut =(carryIns >> 4)& 1;'後,這就是你需要添加的。 –

4

另一種可能更容易理解的方法。當執行總和:

  • 註冊總是被設置爲結果
  • 設置的第7位,如果結果爲0x00
  • 半進設置權當四位操作數總和溢出
  • 溢出在兩個操作數都爲正且簽名總和爲負或兩個操作數都爲負且簽名總和爲正時設置爲
  • 加/減復位
  • 攜帶如果無符號和溢出0xFF的
+1

很好的回顧。爲了進一步闡明:「Add/Sub被重置」,因爲如果最後的操作是減法,'N'只會被顯式設置*。 (我認爲這僅用於'DAA'指令。) – usr2564301

+0

'7位'是什麼意思? 7,從0開始倒數​​? – lakesare