Arithmetic Group

Arithmetic instructions are many of the 8080's 256 opcodes and include the various flavors of add and subtract. Most of the arithmetic instructions operate on register A and store the result into A. (Register A is also called the accumulator).

The interesting thing to note about these instructions is that they effect the condition codes. Condition codes (also called flags) are set by the result of a completed instruction. Not all instructions effect the flags, and not all instruction that effect flags will effect every flag.

8080 Flags

The 8080's flags are named Z, S, P, CY, and AC.

The condition codes are used by conditional branching instructions, for instance JZ will only branch if the Z flag is set.

Most of the instructions have 3 forms, register, immediate, and memory. Let's implement a few here to get their forms and see what it is like to work with the condition codes. (Note that I am not implementing auxillary carry since I know it is not used. If I implemented it, I couldn't test it.)

Register Form

Here are 2 register form instructions implemented; in the first one I draw out the code to make it clear what is going on, and the second is a more compact representation that does the same thing.

    case 0x80:      //ADD B    
        {    
            // do the math with higher precision so we can capture the    
            // carry out    
            uint16_t answer = (uint16_t) state->a + (uint16_t) state->b;    

            // Zero flag: if the result is zero,    
            // set the flag to zero    
            // else clear the flag    
            if ((answer & 0xff) == 0)    
                state->cc.z = 1;    
            else    
                state->cc.z = 0;    

            // Sign flag: if bit 7 is set,    
            // set the sign flag    
            // else clear the sign flag    
            if (answer & 0x80)    
                state->cc.s = 1;    
            else    
                state->cc.s = 0;    

            // Carry flag    
            if (answer > 0xff)    
                state->cc.cy = 1;    
            else    
                state->cc.cy = 0;    

            // Parity is handled by a subroutine    
            state->cc.p = Parity( answer & 0xff);    

            state->a = answer & 0xff;    
        }    

    //The code for ADD can be condensed like this    
    case 0x81:      //ADD C    
        {    
            uint16_t answer = (uint16_t) state->a + (uint16_t) state->c;    
            state->cc.z = ((answer & 0xff) == 0);    
            state->cc.s = ((answer & 0x80) != 0);    
            state->cc.cy = (answer > 0xff);    
            state->cc.p = Parity(answer&0xff);    
            state->a = answer & 0xff;    
        }    

I am emulating the 8-bit math instructions by using a 16-bit number. That makes it easy to figure out if the math generated a carry out of it.

Immediate Form

The immediate form is the almost the same except the source of the addend is the byte after the instruction. Since "opcode" is a pointer to the current instruction in memory, opcode[1] will be the immediately following byte.

    case 0xC6:      //ADI byte    
        {    
            uint16_t answer = (uint16_t) state->a + (uint16_t) opcode[1];    
            state->cc.z = ((answer & 0xff) == 0);    
            state->cc.s = ((answer & 0x80) != 0);    
            state->cc.cy = (answer > 0xff);    
            state->cc.p = Parity(answer&0xff);    
            state->a = answer & 0xff;    
        }    

Memory Form ####

In the memory form, the addend is the byte pointed to by the address stored in the HL register pair.

    case 0x86:      //ADD M    
        {    
            uint16_t offset = (state->h<<8) | (state->l);    
            uint16_t answer = (uint16_t) state->a + state->memory[offset];    
            state->cc.z = ((answer & 0xff) == 0);    
            state->cc.s = ((answer & 0x80) != 0);    
            state->cc.cy = (answer > 0xff);    
            state->cc.p = Parity(answer&0xff);    
            state->a = answer & 0xff;    
        }    

Notes

The rest of the arithmetic instructions are implemented similarly. Some notes:

← Prev: emulator-shell   Next: branch-group →


Post questions or comments on Twitter @realemulator101, or if you find issues in the code, file them on the github repository.