2011-11-07 12 views
21

He estado al tanto de la implementación de ADD A, r conjunto de códigos de operación en mi núcleo Z80. Tuve un poco de confusión sobre las banderas de acarreo y desbordamiento que creo que he clavado, pero quería ponerlo en la comunidad para verificar que estoy en lo correcto.Banderas de desbordamiento y transporte en Z80

Básicamente, por lo que puedo ver, la ALU en el Z80 no se preocupa por las operaciones con firma/sin firmar, solo agrega bits. Esto significa que si se agregan dos valores de 8 bits y causa un valor de 9 bits como resultado de su adición, se establecerá el indicador de acarreo. Esto incluye agregar dos números de complemento de dos negativos, por ejemplo -20 (11101100) y -40 (11011000), ya que aunque el resultado es -60 (11000100), el resultado es en realidad un valor de 9 bits 1 1100 0100. Esto seguramente significa si se agregan dos valores de complemento de dos negativos, la bandera de acarreo siempre se establecerá, incluso cuando no haya condiciones de desbordamiento, ¿estoy en lo cierto?

En segundo lugar, decidí que para detectar un desbordamiento en esta instrucción, utilizaría el bit 7 de ambos operandos, y si el resultado fuera 10000000, entonces definitivamente no hay desbordamiento; si el resultado es 00000000, entonces podría ser un desbordamiento ya que los signos son los mismos, y por lo tanto, el bit 7 de XOR del resultado de la suma con el bit 7 de cualquiera de los operandos, y si el resultado es 10000000, se produce un desbordamiento y configuro el P/V bandera de desbordamiento ¿Estoy aquí también?

Lo siento por una pregunta tan enrevesada, estoy bastante seguro de que estoy en lo cierto, pero necesito saber antes de seguir con innumerables instrucciones basadas en esta lógica. Muchas gracias.

Respuesta

31

Los bits del resultado se obtienen de la suma truncada de enteros sin signo. La instrucción add no se preocupa por el signo aquí ni le importa su propia interpretación de los enteros como firmados o no. Simplemente agrega como si los números no estuvieran firmados.

El indicador de acarreo (o tomar prestado en caso de resta) es el noveno bit inexistente de la suma de los enteros sin signo de 8 bits. Efectivamente, este indicador significa un desbordamiento/subdesbordamiento para agregar/subde números enteros sin signo. Nuevamente, add no se preocupa por los signos aquí, solo agrega como si los números no estuvieran firmados.

Agregar dos números negativos de complemento a 2 dará como resultado el ajuste del indicador de acarreo en 1, correcto.

El indicador de desbordamiento muestra si se ha producido un desbordamiento/desbordamiento para agregar/sumar enteros. Para configurar el indicador de desbordamiento, la instrucción trata los números como firmados (al igual que los trata como no firmados para el indicador de acarreo y los 8 bits del resultado).

La idea de establecer el indicador de desbordamiento es simple. Supongamos que firmas-amplías tus enteros de 8 bits con signo a 9 bits, es decir, solo copias el 7mo bit a un 8vo bit extra. Se producirá un desbordamiento/desbordamiento si la suma/diferencia de 9 bits de estos enteros firmados de 9 bits tiene valores diferentes en los bits 7 y 8, lo que significa que la suma/resta ha perdido el signo del resultado en el 7mo bit y lo usó para el la magnitud del resultado, o, en otras palabras, los 8 bits no pueden acomodar el bit de signo y una magnitud tan grande.

Ahora, el bit 7 del resultado puede diferir del signo imaginario bit 8 si y solo si el acarreo en la punta 7 y el acarreo en la punta 8 (= carga del bit 7) son diferentes. Eso es porque comenzamos con los sumandos que tienen el bit 7 = bit 8 y solo los diferentes arrastres en ellos pueden afectarlos en el resultado de diferentes maneras.

bandera Así desbordamiento = llevar a cabo-pabellón lleven XOR del bit en el bit 6 7.

Tanto mi y sus formas de calcular el indicador de desbordamiento son correctas. De hecho, ambos se describen en el Z80 CPU User's Manual en la sección "Indicadores de estado de Z80".

Así es como se puede emular la mayor parte de la instrucción ADC en C, en la que no tiene acceso directo a las banderas de la CPU y no puede sacar el máximo provecho de la instrucción ADC de la CPU emulando:

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

salida:

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 

puede cambiar #if 0 a #if 1 utilizar el método basado en la comparación de inicio de sesión para el cálculo de desbordamiento. El resultado será el mismo. A primera vista, es un poco sorprendente que el método basado en signos también se ocupe del equipaje de mano.

Tenga en cuenta que al usar mi método en el que puedo calcular todos los carry-ins en los bits 0 a 7, también puede obtener de forma gratuita el valor de la bandera half-carry (acarreo del bit 3 al bit 4) que se necesita para la DAA instrucción.

EDIT: He agregado una función para la resta con el préstamo (instrucción SBC/SBB) y los resultados.

+0

Esto es perfecto - muchas gracias :-) Yo sabía que estaba en la dirección correcta. Gracias también por su muestra de código. De hecho, estoy usando Java (ya que estoy tratando de que sea un emulador de sistema maestro completamente multiplataforma cuando esté hecho), aunque puedo entender lo suficiente C para ver de qué se trata. Lo siento si mi pregunta parecía simple, es solo que tengo que enseñarme un montón de matemáticas binarias mientras voy con este proyecto, hasta ahora, parece que lo he comprendido :-) – PhilPotter1987

+0

Gracias por su explicación, es realmente preciso . Descubrí la bandera de la mitad de la cola al hacer 'halfCarryOut = carryIn? ((a & 0x0F)> = 0x0F - (a & 0x0F)): ((a & 0x0F)> 0x0F - (a & 0x0F)); halfCarryOut = ((res^a^b) >> 4)^halfCarryOut; ', debería ser correcto. – Jack

+1

@Jack Si lo ha probado y funciona, está bien (no lo voy a validar). Pero se puede hacer de manera más simple, como indiqué al final de la respuesta. Usa la variante de código entre #else y #endif. Después de 'carryIns = * acc^a^b;' do 'halfCarryOut = (carryIns >> 4) & 1;', eso es todo lo que necesita agregar. –

4

Otra forma de ver esto que quizás sea más fácil de entender. Cuando se realiza una suma:

  • sesión siempre se establece en el bit 7 del resultado
  • cero se establece si el resultado es 0x00
  • half-carry se establece cuando el mordisco derecha suma de operandos desbordamientos
  • Desbordamiento se establece cuando ambos operandos son positivos y la suma de signos es negativa o ambos operandos son negativos y la suma firmada es positiva
  • Add/Sub se restablece
  • Realizar se establece si la suma sin signo desborda 0xFF
+1

Buen resumen. Para aclarar un poco más: "Add/Sub se reinicia" porque 'N' solo se establece explícitamente * set * si la última operación fue una resta. (Creo que esto se usa solo para la instrucción 'DAA'.) – usr2564301

+0

¿Qué quiere decir con 'bit 7'? Séptimo, contando hacia atrás, comenzando desde 0? – lakesare

Cuestiones relacionadas