private void ComputeFlagsForIOBlockInstruction(IOBlockInstructionType instructionType) { // The out instructions behave differently than the in instructions, which doesn’t make the CPU very symmetrical. // First of all, all instructions affect the following flags: F = 0; // SF, ZF, YF, XF flags Affected by decreasing register B, as in DEC B. // For OUT instructions, B has already been decremented when we compute flags byte decB = B; // For IN instructions, B has not yet been decremented when we compute flags, so we consider B-1 if (instructionType == IOBlockInstructionType.IND || instructionType == IOBlockInstructionType.INI) { decB = (byte)(B - 1); } // Flags bit 7 - SF flag - Set if the 2-complement value is negative. It's simply a copy of the most signifcant bit of the result. F |= (byte)(decB & B10000000); // Flags bit 6 - ZF flag Set if the result is zero. if (decB == 0) F |= B01000000; // Flags bit 5 - YF flag - A copy of bit 5 of the result. // Flags bit 3 - XF flag - A copy of bit 3 of the result. F |= (byte)(decB & B00101000); // NF flag A copy of bit 7 of the value read from or written to an I/O port. NF = (InternalDataBus & B10000000) != 0; int k = 0; // And now the for OUTI/OTIR/OUTD/OTDR instructions. if (instructionType == IOBlockInstructionType.OUT) { // Take state of the L after the increment or decrement of HL; add the value written to the I/O port to; call that k for now. // HF and CF Both set if ((HL) + L > 255) // PF The parity of ((((HL) + L) & 7) xor B) k = InternalDataBus + L; } else { // INI/INIR/IND/INDR use the C register in stead of the L register. // There is a catch though, because not the value of C is used, but C + 1 if it’s INI/INIR or C - 1 if it’s IND/INDR. // So, first of all INI/INIR: if (instructionType == IOBlockInstructionType.INI) { // HF and CF Both set if ((HL) + ((C + 1) & 255) > 255) // PF The parity of (((HL) + ((C + 1) & 255)) & 7) xor B) k = InternalDataBus + ((C + 1) & 255); } // And last IND/INDR: else if (instructionType == IOBlockInstructionType.IND) { // HF and CF Both set if ((HL) + ((C - 1) & 255) > 255) // PF The parity of (((HL) + ((C - 1) & 255)) & 7) xor B) k = InternalDataBus + ((C - 1) & 255); } } // If k > 255, then the CF and HF flags are set. // HF and CF Both set if ((HL) + L > 255) CF = k > 255; HF = k > 255; // The PF flags is set like the parity of k bitwise and’ed with 7, bitwise xor’ed with B. // PF The parity of ((((HL) + L) & 7) xor B) PF = numberOfBitsInByteParityTable[(byte)((k & 7) ^ decB)]; if (TraceMicroInstructions) { TraceMicroInstruction(new MicroInstruction(Z80MicroInstructionTypes.FlagsOperationComputeFlagsForIOBlockInstruction)); } }
private void ComputeFlagsForIOBlockInstruction(IOBlockInstructionType instructionType) { // The out instructions behave differently than the in instructions, which doesn’t make the CPU very symmetrical. // First of all, all instructions affect the following flags: F = 0; // SF, ZF, YF, XF flags Affected by decreasing register B, as in DEC B. // For OUT instructions, B has already been decremented when we compute flags byte decB = B; // For IN instructions, B has not yet been decremented when we compute flags, so we consider B-1 if (instructionType == IOBlockInstructionType.IND || instructionType == IOBlockInstructionType.INI) { decB = (byte)(B - 1); } // Flags bit 7 - SF flag - Set if the 2-complement value is negative. It's simply a copy of the most signifcant bit of the result. F |= (byte)(decB & B10000000); // Flags bit 6 - ZF flag Set if the result is zero. if (decB == 0) { F |= B01000000; } // Flags bit 5 - YF flag - A copy of bit 5 of the result. // Flags bit 3 - XF flag - A copy of bit 3 of the result. F |= (byte)(decB & B00101000); // NF flag A copy of bit 7 of the value read from or written to an I/O port. NF = (InternalDataBus & B10000000) != 0; int k = 0; // And now the for OUTI/OTIR/OUTD/OTDR instructions. if (instructionType == IOBlockInstructionType.OUT) { // Take state of the L after the increment or decrement of HL; add the value written to the I/O port to; call that k for now. // HF and CF Both set if ((HL) + L > 255) // PF The parity of ((((HL) + L) & 7) xor B) k = InternalDataBus + L; } else { // INI/INIR/IND/INDR use the C register in stead of the L register. // There is a catch though, because not the value of C is used, but C + 1 if it’s INI/INIR or C - 1 if it’s IND/INDR. // So, first of all INI/INIR: if (instructionType == IOBlockInstructionType.INI) { // HF and CF Both set if ((HL) + ((C + 1) & 255) > 255) // PF The parity of (((HL) + ((C + 1) & 255)) & 7) xor B) k = InternalDataBus + ((C + 1) & 255); } // And last IND/INDR: else if (instructionType == IOBlockInstructionType.IND) { // HF and CF Both set if ((HL) + ((C - 1) & 255) > 255) // PF The parity of (((HL) + ((C - 1) & 255)) & 7) xor B) k = InternalDataBus + ((C - 1) & 255); } } // If k > 255, then the CF and HF flags are set. // HF and CF Both set if ((HL) + L > 255) CF = k > 255; HF = k > 255; // The PF flags is set like the parity of k bitwise and’ed with 7, bitwise xor’ed with B. // PF The parity of ((((HL) + L) & 7) xor B) PF = numberOfBitsInByteParityTable[(byte)((k & 7) ^ decB)]; if (TraceMicroInstructions) { TraceMicroInstruction(new MicroInstruction(Z80MicroInstructionTypes.FlagsOperationComputeFlagsForIOBlockInstruction)); } }