2011-11-07 3 views
21

Je me suis tourné vers l'implémentation de l'ensemble ADD A, r d'opcodes sur mon cœur Z80. J'ai eu un peu de confusion au sujet des drapeaux de portage et de débordement que je pense avoir cloués, mais je voulais que ce soit remis à la communauté pour vérifier que j'ai raison. Fondamentalement, d'après ce que je peux voir, l'ALU dans le Z80 ne se soucie pas des opérations signées/non signées, il ajoute juste des bits. Cela signifie que si deux valeurs de 8 bits sont ajoutées ensemble et provoquent une valeur de 9 bits à la suite de leur addition, le drapeau de report sera défini. Cela inclut l'ajout de deux nombres de complément à deux négatifs, par exemple -20 (11101100) et -40 (11011000), car bien que le résultat soit -60 (11000100), le résultat est en réalité une valeur de 9 bits 1 1100 0100. Cela signifie sûrement si vous ajoutez deux valeurs de complément à deux négatifs, l'indicateur de retenue sera toujours défini, même s'il n'y a pas de condition de dépassement de capacité - ai-je raison? Deuxièmement, j'ai décidé que pour détecter un débordement dans cette instruction, je voudrais XOR bit 7 des deux opérandes, et si le résultat était 10000000, alors il n'y a certainement pas de débordement - si le résultat de 00000000 alors il pourrait y avoir être un débordement comme les signes sont les mêmes, et je voudrais donc XOR bit 7 du résultat de l'addition avec le bit 7 de l'un ou l'autre opérande, et si le résultat de ceci est 10000000 alors un débordement s'est produit et j'ai mis le P/V drapeau de débordement. Suis-je ici aussi? Désolé pour une question si alambiquée, je suis sûr que j'ai raison, mais j'ai besoin de savoir avant de continuer avec d'innombrables autres instructions basées sur cette logique. Merci beaucoup.Drapeaux de débordement et de transport sur Z80

Répondre

31

Les bits du résultat sont obtenus à partir de la somme tronquée d'entiers non signés. L'instruction add ne se soucie pas du signe ici et ne se soucie pas non plus de votre propre interprétation des entiers comme signés ou non signés. Il ajoute simplement comme si les nombres étaient non signés. Le drapeau de report (ou emprunter en cas de soustraction) est ce 9ème bit inexistant à partir de l'addition des entiers non signés de 8 bits. Effectivement, cet indicateur signifie un débordement/sous-dépassement pour l'ajout/sous-nombre d'entiers non signés. Encore une fois, ajouter ne se soucie pas du tout des signes ici, il ajoute simplement comme si les chiffres n'étaient pas signés. L'ajout de deux nombres de complément négatifs de 2 entraînera le réglage du drapeau de report à 1, correct. L'indicateur de débordement indique s'il y a eu ou non un débordement/sous-dépassement pour l'ajout/le sous-ensemble d'entiers signés. Pour définir l'indicateur de débordement, l'instruction traite les nombres comme signés (tout comme ils les traitent comme non signés pour le drapeau de report et les 8 bits du résultat).

L'idée derrière la définition du drapeau de débordement est simple. Supposons que vous signiez - étendez vos entiers signés 8 bits à 9 bits, c'est-à-dire copiez simplement le 7ème bit à un 8ème bit supplémentaire. Un débordement/sous-dépassement se produira si la somme/différence de 9 bits de ces entiers signés à 9 bits a des valeurs différentes dans les bits 7 et 8, signifiant que l'addition/soustraction a perdu le signe du résultat dans le 7ème bit et l'a utilisé pour le l'amplitude du résultat, ou, en d'autres termes, les 8 bits ne peuvent pas accepter le bit de signe et une telle amplitude. Or, le bit 7 du résultat peut différer du bit de signe imaginaire 8 si et seulement si le report dans le bit 7 et le report dans le bit 8 (= exécution du bit 7) sont différents. C'est parce que nous commençons avec les addends ayant le bit 7 = bit 8 et seulement des carry-ins différents dans eux peuvent les affecter dans le résultat de différentes manières.

drapeau donc trop-plein = report sur porte-drapeau du XOR de bit 6 dans le bit 7.

My et vos façons de calculer le drapeau de débordement sont corrects. En fait, les deux sont décrits dans la section "Indicateurs d'état Z80" de la section Z80 CPU User's Manual.

Voilà comment vous pouvez imiter la plupart de l'instruction ADC en C, où vous ne disposez pas d'un accès direct aux drapeaux de la CPU et ne peut pas profiter pleinement de l'instruction ADC de la CPU émule:

#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; 
} 

sortie:

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 

Vous pouvez modifier #if 0 à #if 1 d'utiliser la méthode de la connexion comparaison pour le calcul de trop-plein. Le résultat sera le même. À première vue, il est un peu surprenant que la méthode basée sur les signes prenne également en charge le report.

S'il vous plaît noter qu'en utilisant ma méthode dans laquelle je calcule tous les carry-ins dans les bits 0 à 7, vous obtenez également gratuitement la valeur du drapeau half-carry (porter du bit 3 au bit 4) DAA instruction.

EDIT: J'ai ajouté une fonction pour la soustraction avec emprunt (instruction SBC/SBB) et les résultats pour cela.

+0

C'est parfait - merci beaucoup :-) Je savais que j'étais dans la bonne direction. Merci également pour votre exemple de code. J'utilise Java (car je souhaite que ce soit un émulateur de système maître multi plate-forme quand c'est fait), bien que je puisse comprendre assez de C pour voir ce que vous êtes sur le sujet. Désolé si ma question semblait simple, c'est juste que je dois m'apprendre beaucoup de maths binaires comme je vais avec ce projet, jusqu'ici je semble l'avoir bien compris :-) – PhilPotter1987

+0

Merci pour votre explication, c'est vraiment précis . J'ai trouvé le drapeau halfprey en faisant 'halfCarryOut = carryIn? ((a & 0x0F)> = 0x0F - (a & 0x0F)): ((a & 0x0F)> 0x0F - (a & 0x0F)); halfCarryOut = ((res^a^b) >> 4)^halfCarryOut; ', cela devrait être correct. – Jack

+1

@Jack Si vous l'avez testé et que cela fonctionne, OK (je ne vais pas le valider). Mais cela peut être fait plus simple comme je l'ai indiqué à la fin de la réponse. Utilisez la variante de code entre #else et #endif. Après 'carryIns = * acc^a^b;' do 'halfCarryOut = (carryIns >> 4) & 1;', c'est tout ce que vous devez ajouter. –

4

Une autre façon de voir ce qui est peut-être plus facile à comprendre. Lorsque vous effectuez une somme:

  • signe est toujours à bit 7 du résultat
  • Zéro est réglé si le résultat est 0x00
  • demi-carry est réglé lorsque le droit grignotage La somme des débordements des opérandes
  • Le débordement est activé lorsque les deux opérandes sont positifs et que la somme signée est négative ou que les deux opérandes sont négatifs et que la somme signée est positive
  • Ajouter/Sub est remis à zéro
  • Carry est réglé si la somme non signée 0xFF déborde
+1

Belle récapitulation. Pour clarifier un peu plus loin: "Add/Sub est réinitialisé" parce que 'N' ne prend explicitement * set * que si la dernière opération était une soustraction. (Je pense que ceci est utilisé uniquement pour l'instruction 'DAA'.) – usr2564301

+0

Que voulez-vous dire par 'bit 7'? 7e, en comptant à rebours, à partir de 0? – lakesare

Questions connexes