Logical Group

This group performs logical operations (see my previous post on logical operations). They are similar in nature to the arithmetic group in that most operations operate on A (the accumulator), and most operations effect the flags. All operate on 8-bits, there are no instructions in this group that effect register pairs.

[http://en.wikipedia.org/wiki/George_Boole]

Boolean refers to mathematician George Boole who worked with logic in the 1800s. He

invented a series of mathematical rules governing reduction of complicated logical

expressions which are used extensively in digital logic design.

Boolean Operations

AND, OR, not (CMP), and exclusive or (XOR) are known as Boolean operations. OR and AND were explained earlier. A not instruction (the 8080 calls it CMA or complement accumulator) simply flips the bits, all 1s become 0s, and all 0s become 1s.

I think of XOR as a "difference detector". Its truth table looks like this:

xyresult
000
011
101
110

There are register, memory, and immediate forms of AND, OR, and XOR. (CMP only has a register instruction). Here is an implementation of a couple of opcodes:

    case 0x2F:                    //CMA (not)    
        state->a = ~state->a    
        //Data book says CMA doesn't effect the flags    
        break;    

    case 0xe6:                    //ANI    byte    
        {    
        uint8_t x = state->a & opcode[1];    
        state->cc.z = (x == 0);    
        state->cc.s = (0x80 == (x & 0x80));    
        state->cc.p = parity(x, 8);    
        state->cc.cy = 0;           //Data book says ANI clears CY    
        state->a = x;    
        state->pc++;                //for the data byte    
        }    
        break;    

Rotate Instructions

These instructions rearrange the bits in the registers. Shift right moves them right by one bit, and shift left moves them left one bit. Like this:

Shift Right(0b00010000) = 0b00001000

Shift Left (0b00000001) = 0b00000010

They might appear to have no use, but they have some tricks up their sleeves. They can be used to multiply and divide by powers of two. Take the shift left example above. 0b00000001 is decimal 1, and shifting it left makes it 0b00000010 which is decimal 2. If you shift it left again, you get 0b00000100 which is 4. Shift left again and you have multiplied by 8. This works for any number you try: 5 (0b00000101) shifted left once equals 10 (0b00001010). Shift left again gives 20 (0b00010100). Shift right does the same thing for divide.

The 8080 doesn't have a multiply instruction, but you can implement it using these instructions. You get bonus points if you can figure out how. I was asked this question in a job interview once. (I got it right, although it took me a few minutes.)

These instructions rotate the accumulator and only effect the carry flag. Here are a couple:

    case 0x0f:                    //RRC    
        {    
            uint8_t x = state->a;    
            state->a = ((x & 1) << 7) | (x >> 1);    
            state->cc.cy = (1 == (x&1));    
        }    
        break;    

    case 0x1f:                    //RAR    
        {    
            uint8_t x = state->a;    
            state->a = (state->cc.cy << 7) | (x >> 1);    
            state->cc.cy = (1 == (x&1));    
        }    
        break;    


Compare

The purpose of CMP and CPI is simply to set the flags (for a branch). They accomplish this with a subtraction that sets the flags but doesn't store the result.

There are register, memory, and immediate versions of it. The implementation is simply subtract without the result stored:

    case 0xfe:                      //CPI  byte    
        {    
        uint8_t x = state->a - opcode[1];    
        state->cc.z = (x == 0);    
        state->cc.s = (0x80 == (x & 0x80));    
        //It isn't clear in the data book what to do with p - had to pick    
        state->cc.p = parity(x, 8);    
        state->cc.cy = (state->a < opcode[1]);    
        state->pc++;    
        }    
        break;    

CMC and STC

These finish out the logical group and are used to set and clear the carry flag.

← Prev: branch-group   Next: io-and-special-group →


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