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.
The 8080's flags are named Z, S, P, CY, and AC.
Z (zero) set to 1 when the result is equal to zero
S (sign) set to 1 when bit 7 (the most significant bit or MSB) of the math instruction is set
P (parity) is set when the answer has even parity, clear when odd parity
CY (carry) set to 1 when the instruction resulted in a carry out or borrow into the high order bit
AC (auxillary carry) is used mostly for BCD (binary coded decimal) math. Read the data book for more details, Space Invaders doesn't use it.
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.)
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.
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; }
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; }
The rest of the arithmetic instructions are implemented similarly. Some notes:
In the carry variants (ADC, ACI, SBB, SUI) you use the carry bit in the calculation as indicated in the data book.
INX and DCX effect register pairs, these instructions do not effect the flags.
DAD is another register pair instruction, it only effects the carry flag
INR and DCR do not effect the carry flag
Post questions or comments on Twitter @realemulator101, or if you find issues in the code, file them on the github repository.