• Please review our updated Terms and Rules here

8080 ADD and ADC example...

alank2

Veteran Member
Joined
Aug 3, 2016
Messages
2,249
Location
USA
Are these used with each other? It seems like I've seen ADD used for the lowest byte and then ADC used for the next higher byte to include any overflow from the ADD, but how does that work when they are both tied to the accumulator?

(warning - I do not know how to program in 8080 yet!)

So if I wanted to BC=BC+DE and the add/adc commands _could_ work on non accumulator registers:

ADD B,D
ADC C,E

But you can't do something like this when they both affect A only, right?

How is ADC used on the 8080?
 
Yup, the basic sequence is like this:

Code:
   MOV    A,E
   ADD    C
   MOV   E,A
   MOV   A,D
   ADC    B
   MOV   D,A

To add BC to DE. Of course, the DAD operation could do it easier and not use A:

Code:
     XCHG   
     DAD     B
     XCHG

However, note that DAD affects only the carry flag.
 
That XCHG/DAD/XCHG is tricky!

So I'm trying to implement the very tricky DAA instruction. Apparently there are small differences between the way it is implemented on 8080 vs 8085 vs Z80 or that seems to be what I've read.

The instructions are clear enough in one of the Intel manuals I've looked at for the 8080:

DAA (Decimal Adjust Accumulator)
The eight-bit number in the accumulator is adjusted
to form two four-bit Binary-Coded-Decimal digits by
the following process:
1. If the value of the least significant 4 bits of the
accumulator is greater than 9 or if the AC flag
is set, 6 is added to the accumulator.
2. If the value of the most significant 4 bits of the
accumulator is now greater than 9, or if the CY
flag is set, 6 is added to the most significant 4
bits of the accumulator.
NOTE: All flags are affected.

I like how they put "is now greater" to suggest that step 1 addition should be taken into account for step 2.

The part that I find confusing is the final "all flags are affected". This is not specific about how the final carry or auxcarry flag is affected.

Logically one has to assume that if the most significant bcd is added to (+0x60), there are two reasons. Either the carry was set, or it was in the 0xa0-0xf0 range and carry wasn't set but needs to be set. Either way, if you add 0x60 carry must be set.

Does the same hold true for the aux carry? If you add 0x6 to the least significant bcd should the aux carry also be set? Does it even have meaning outside of the two bcd values being added? Obviously the carry could be used to continue adding bcd numbers. What did real 8080 silicon do?

edit: actually I suppose the aux carry flag should be cleared after a DAA - since it has been normalized and you don't want another one normalizing it again? Although the carry could very well be set and another DAA would trigger another +0x60 you didn't want too. I guess someone with a real 8080 could step some instructions to find out - I know the auxcarry isn't testable, but you can always run a DAA and see what it does to the A.
 
Last edited:
It's easy to "over think" these things. For most purposes, the AC can be ignored. You can't directly test it, or use it. As far as I can recall, there are no instructions that depend on the AC value from previous instructions. I believe it is simply an internal flag used for various purposes and mentioned for transparency. For DAA, just think of the carry in the normal sense. If you had 99H in the accumulator, added 1 to it, and did DAA, you get a carry and 00H (i.e. 0100H - BCD 100). Of course, there are plenty of non-obvious uses like the famous sequence to convert a binary value 0-15 into an ASCII HEX character:

ADI 90H
DAA
ACI 40H
DAA

It takes a little head-scratching, but looking at how this sequence works might explain those instructions. As strange as it looks, the "normal" explanation of the instructions does reveal how the sequence performs its "magic".
 
Thanks guys - I'm pretty sure I have the carry behavior set right because it has to work a certain way to carry into the next one, but the aux carry behavior could really go either way. Perhaps it doesn't matter, but I'd like to emulate it properly the way the 8080 does it if I can figure it out. Too bad I don't have a real 8080 or I could do some opcode testing - do you guys know of any online 8080's running a monitor? I could order an 8080 cpu, but I'm not sure it would work in my zeta2 sbc (romwbw) or kaypro, probably both have Z80 specific bios code. I know it isn't a huge deal with the aux carry state after DAA, but I'd like it to be accurate if I can make it so.

What I have now that assumes aux carry does the same thing carry does which may or may not be right:
Code:
static inline void daa()
  {
    if (CPUFLAG_AUXCARRY || (CPUREGS_A & 0x0f)>0x09)
      {
        CPUREGS_A+=(uint8_t)0x06;
        CPUFLAG_AUXCARRY=1;
      }
    if (CPUFLAG_CARRY || CPUREGS_A>0x99)
      {
        CPUREGS_A+=(uint8_t)0x60;
        CPUFLAG_CARRY=1;
      }
    zero_sign_parity_flags(CPUREGS_A);
  }
 
Ah, I missed that you were writing an emulation of the 8080. The emulation I am using does this for DAA (in JAVA):

Code:
        private void daa() {
                int suma = 0;
                boolean carry = carryFlag;

                if ((sz5h3pnFlags & HALFCARRY_MASK) != 0 || (regA & 0x0f) > 0x09) {
                        suma = 6;
                }

                if (carry || (regA > 0x99)) {
                        suma |= 0x60;
                }

                if (regA > 0x99) {
                        carry = true;
                }

                if ((sz5h3pnFlags & ADDSUB_MASK) != 0) {
                        sub(suma);
                        sz5h3pnFlags = (sz5h3pnFlags & HALFCARRY_MASK) | sz53pn_subTable[regA];
                } else {
                        add(suma);
                        sz5h3pnFlags = (sz5h3pnFlags & HALFCARRY_MASK) | sz53pn_addTable[regA];
                }

                carryFlag = carry;
                // Los add/sub ya ponen el resto de los flags
                flagQ = true;
        }

This is for a Z80, and I'm not sure if the 8080 has the equivalent of the "add/sub bit" - which essentially tells whether the previous ALU instruction was add-like or subtract-like. It also uses tables to get some of the flags bits. But note that DAA does not alter the half-carry (aux carry) bit (assuming this emulation is accurate).

A quick search found an i8080 emulator at https://github.com/superzazu/8080, which does this for DAA:

Code:
static inline void i8080_daa(i8080* const c) {
    bool cy = c->cf;
    uint8_t correction = 0;

    const uint8_t lsb = c->a & 0x0F;
    const uint8_t msb = c->a >> 4;

    if (c->hf || lsb > 9) {
        correction += 0x06;
    }
    if (c->cf || msb > 9 || (msb >= 9 && lsb > 9)) {
        correction += 0x60;
        cy = 1;
    }
    i8080_add(c, &c->a, correction, 0);
    c->cf = cy;
}

I chose to use someone else's emulation of the Z80 because I didn't want to hassle with what you are going through. Of course, you risk picking up someone else's mistakes, too. I then build various computer platforms and GUIs around that CPU emulation.
 
Last edited:
I am doing it for the 8080 for now, someday I want to expand to the 8085 and z80 later.

I made up some code (which not being an 8080 coder is more than I usually do):

Code:
3e 00	mvi a,00h
c6 11	adi a,11h	;aux carry off, right nibble 0-9
27	daa		;after running this, the carry should be 0
3e 00	mvi a,00h
27	daa		;if a moves to 06, then the previous daa left aux carry set for some reason

3e 05	mvi a,05h
c6 05	adi a,05h	;aux carry off, right nibble a-f
27	daa		;after running this, the carry should be 0
3e 00	mvi a,00h
27	daa		;if a moves to 06, then the previous daa left aux carry set for some reason

3e 07	mvi a,07h
c6 09	adi a,09h	;aux carry on, right nibble 0-9
27	daa		;after running this, the carry should be 0
3e 00	mvi a,00h
27	daa		;if a moves to 06, then the previous daa left aux carry set for some reason

3e 0f	mvi a,0fh
c6 0f	adi a,0fh	;aux carry on, right nibble a-f
27	daa		;after running this, the carry should be 0
3e 00	mvi a,00h
27	daa		;if a moves to 06, then the previous daa left aux carry set for some reason

An online emulator (https://www.tramm.li/i8080/emu8080.html) leaves the aux carry flag off after all DAA operations.
SIMH turns it on for operations 2 and 4, but not 1 and 3.

Does anyone with a real 8080 want to step these and see what they do?
 
Based on what I'm seeing in emulators, I was incorrect to assert that half-carry does not change. DAA will perform an ADD internally (or possibly SUB on Z80), which will alter the half-carry according to the normal rules for ADD.
 
I suspect that the DAA on the x86 architecture behaves identically to the 8080 (pretty much has to, because of compatibility issues early on). So you can check your results using a real 8088/8086.
 
Based on what I'm seeing in emulators, I was incorrect to assert that half-carry does not change. DAA will perform an ADD internally (or possibly SUB on Z80), which will alter the half-carry according to the normal rules for ADD.

This is what I was thinking - that when it performs the add of 6, that might or might not cause the aux carry, probably because it uses the same addition logic. Probably the carry works the same way. This explains the SIMH behavior which is probably correct.

I suspect that the DAA on the x86 architecture behaves identically to the 8080 (pretty much has to, because of compatibility issues early on). So you can check your results using a real 8088/8086.

I kept reading pages covering how there are minor differences or fixes between the 8080 and 8085 (and also the Z80) on this, so it is tough to know exactly what a certain ones behavior might be without testing it. I know the Z80 adds a feature where it will work for subtraction too and I don't think the 8080 supports that, but I'm not sure about the 8085. Oh why oh why doesn't someone have their 8080 and 8085 strung up to the Internet with a monitor when you want one! :)
 
I've got 8085 and 8080 systems, but I don't see the point of putting these low-powered critters on the web.

8085 CPUs have the property that it doesn't take much to get a workable system going. Three-chip implementations aren't unusual.
 
Here's an idea: Got an XT compatible with a NEC V20 cpu? The V20 follows the 8080 instruction set pretty faithfully. You can load up the PC with something like CPMulator and run your 8080 tests.
 
I wish I had a V20 Chuck - would you mind entering the 32 opcodes on your 8080 and stepping through them to see what the A value is after byte 8, 16, 24, and 32. It should either be 0 or 6 depending on whether the monitor/ddt do anything to alter the aux carry flag. I could make a full blown CP/M test program that outputs the result to the console as a Y or N if that is easier. If you are busy then don't sweat it, but I'm always looking for a reason to turn something old on!

3E 00 C6 11 27 3E 00 27
3E 05 C6 05 27 3E 00 27
3E 07 C6 09 27 3E 00 27
3E 0F C6 0F 27 3E 00 27
 
Just for reference, I ran this on my Z80 emulation and got "@F@F". Is that what you'd expect as output?
 
Back
Top