I bit del risultato si ottengono dalla somma troncata di numeri interi senza segno. L'aggiunta di istruzioni non interessa il segno qui, né interessa la tua interpretazione degli interi come firmati o non firmati. Aggiunge solo come se i numeri non fossero firmati.
Il flag di trasporto (o prendere in prestito in caso di sottrazione) è quel 9 ° bit inesistente dall'aggiunta degli interi senza segno a 8 bit. In effetti, questo flag indica un overflow/underflow per aggiungere/sub di interi non firmati. Ancora una volta, aggiungere non si preoccupa dei segni qui, aggiunge solo come se i numeri non fossero firmati.
L'aggiunta di due numeri di complemento a 2 negativi comporterà l'impostazione del flag di trasporto su 1, corretta.
Il flag di overflow indica se c'è stato un overflow/underflow per aggiungere/sub di interi con segno. Per impostare il flag di overflow, l'istruzione considera i numeri come firmati (proprio come li considera come non firmati per il flag carry e gli 8 bit del risultato).
L'idea alla base dell'impostazione del flag di overflow è semplice. Supponete di firmare-estendere i vostri interi con segno a 8 bit a 9 bit, cioè copiare semplicemente il 7 ° bit in un 8 ° bit in più. Si verificherà un overflow/underflow se la somma/differenza di 9 bit di questi numeri interi con segno a 9 bit ha valori diversi nei bit 7 e 8, il che significa che l'addizione/sottrazione ha perso il segno del risultato nel 7 ° bit e lo ha usato per grandezza del risultato, o, in altre parole, gli 8 bit non possono contenere il bit del segno e una grandezza così grande.
Ora, il bit 7 del risultato può essere diverso dal bit 8 del segno immaginario se e solo se il trasferimento nel bit 7 e il trasferimento nel bit 8 (= esecuzione del bit 7) sono diversi. Questo perché iniziamo con gli addendi che hanno bit 7 = bit 8 e solo diversi carry-in in essi possono influenzarli nel risultato in modi diversi.
bandiera Così trabocco = carry-out bandiera XOR trasportare da bit 6 nel bit 7.
Sia il mio e il tuo modo di calcolare il flag di overflow sono corrette. Infatti, entrambi sono descritti nella sezione Z80 CPU User's Manual nella sezione "Indicatori di stato dello Z80".
Ecco come è possibile emulare la maggior parte delle istruzioni ADC in C, in cui non si dispone di accesso diretto alle bandiere della CPU e non può sfruttare appieno l'istruzione ADC della CPU emulare:
#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;
}
uscita:
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
È possibile modificare #if 0
a #if 1
utilizzare il metodo di accesso basato sui confronti per il calcolo di troppo pieno. Il risultato sarà lo stesso. A prima vista, è un po 'sorprendente che il metodo basato sui segnali si occupi anche del carry-in.
Si prega di notare che usando il mio metodo in cui calcolare tutte carry-in in bit da 0 a 7, si ottiene anche gratuitamente il valore della bandiera half-carry
(portare da bit 3 al bit 4) che serve per la DAA
istruzioni.
MODIFICA: Ho aggiunto una funzione per sottrazione con prestito (istruzione SBC/SBB) e risultati per esso.
Questo è perfetto - vi ringrazio molto :-) sapevo di essere nella giusta direzione. Grazie anche per il tuo esempio di codice. In realtà sto usando Java (dato che sto puntando a questo per essere un emulatore di sistema master completamente multipiattaforma quando è fatto), anche se posso capire abbastanza C per vedere di cosa stai parlando. Scusate se la mia domanda sembrava semplice, è solo che mi sto insegnando un sacco di matematica binaria mentre vado con questo progetto, finora mi sembra di averlo afferrato però :-) – PhilPotter1987
Grazie per la spiegazione, è davvero preciso . Ho scoperto la bandiera halfcarry facendo 'halfCarryOut = carryIn? ((a & 0x0F)> = 0x0F - (a & 0x0F)): ((a & 0x0F)> 0x0F - (a & 0x0F)); halfCarryOut = ((res^a^b) >> 4)^halfCarryOut; ', dovrebbe essere corretto. – Jack
@Jack Se lo hai testato e funziona, OK (non ho intenzione di convalidarlo). Ma può essere fatto più semplice, come ho indicato alla fine della risposta. Usa la variante del codice tra #else e #endif. Dopo 'carryIns = * acc^a^b;' fai 'halfCarryOut = (carryIns >> 4) & 1;', questo è tutto ciò che devi aggiungere. –