• Keine Ergebnisse gefunden

USING THE FLAGS INCORRECTLY

Im Dokument Assembly Language Subroutines (Seite 155-159)

Z80 instructions have widely varying effects on the flags. There are few general rules, and even instructions with similar meanings may work differently. Cases that require special' caution are

· Data transfer instructions such as LD and EX (except EX AF, AF') do not affect any flags. You may need an otherwise superfluous arithmetic or logical instruction (such as AND A, DEC, INC, or OR A) to set the flags.

· The Carry flag acts as a borrow after CP, SBC, or SUB instructions; that is, the Carry is set if the 8-bit unsigned subtraction requires a borrow. If, however, you implement subtraction by adding the two's or ten's complement of the subtrahend, the Carry is an inverted borrow; that is, the Carry is cleared if the 8-bit unsigned subtraction requires a borrow and set if it does not.

• After a comparison (CP), the Zero flag indicates whether the operands are equal; it is set if they are equal and cleared if they are not. There is an obvious source of confusion here - JZ means "j urn p if the result is 0, " that is, "jump ifthe Zero flag is 1. "

JNZ, of course, has the opposite meaning.

· When comparing unsigned numbers, the Carry flag indicates which number is larger. CP sets Carry if the accumulator is less than the other operand and clears it if the accumulator is greater than or equal to the other operand. Note that the Carry is cleared if the operands are equal. If this division of cases ("greater than or equal" and

"less than'') is not what you want (that is, you wantthe division to be "greater than" and

"less than or equal''), you can reverse the subtraction, subtract 1 from the accumulator, or add 1 to the other operand.

· In comparing signed numbers, the Sign flag indicates which operand is larger unless two's complement overflow occurs (see Chapter 1). CP sets the Sign flag ifthe accumulator is less than the other operand and clears it if the accumulator is greater

CHAPTER 3 COMMON PROGRAMMING ERRORS

143

than or equal to the other operand. Note that comparing equal operands clears the Sign flag. As with the unsigned numbers, you can handle the equality case in the opposite way by adjusting either operand or by reversing the subtraction. If overflow occurs (signified by the setting of the Parity / Overflow flag), the sense ofthe Sign flag is inverted.

· All logical instructions except CPL clear the Carry flag. AND A or OR A is, in fact, a quick, simple way to clear Carry without affecting any registers. CPL affects no flags at all (XOR OFFH is an equivalent instruction that affects the flags).

· The common way to execute code only if a condition is true is to branch around it if the condition is false. For example, to increment register B if Carry is I, use the sequence

NEXT:

,-IR NC, NEXT INC B NOP The branch occurs if Carry is O.

· Many 16-bit arithmetic instructions have little effect on the flags. INC and DEC do not affect any flags when applied to register pairs or index registers; ADD HL and ADD xy affect only the Carry flag. The limited effects on the flags show that these instructions are intended for address arithmetic, not for the processing of 16-bit data.

Note, however, that ADC HL and SBC HL affect all the flags and can be used for ordinary processing of 16-bit data.

· INC and DEC do not affect the Carry flag. This allows them to be used for counting in loops that perform multiple byte arithmetic. (The Carry is needed to transfer carries or borrows between bytes.) The 8-bit versions of INC and DBC do, however, affect the Zero and Sign flags, and you can use those effects to determine whether a carry or borrow occurred.

· The special instructions RLCA, RLA, RRCA, and RRA affect only the Carry flag.

· Special-purpose arithmetic and logical instructions such as ADD A,A (logical left shift accumulator), ADC A,A (rotate left accumulator), SUB A (clear accumulator), and AND A or OR A (test accumulator) affect all the flags.

· PUSH and POP instructions do not affect the flags, except for POP AF which changes all the flags. Remember, AF consists of the accumulator (MSB) and the flags (LSB).

Examples

1. The sequence

LD A, (2040H) JR Z,DONE

144

Z80 ASSEMBLY LANGUAGE SUBROUTINES

has unpredictable results, since LD does not affect the flags. To produce a jump if memory location 204016 contains 0, use

LD A.(2040H)

AND A JTEST ACCUMULATOR

JR Z.DONE

OR A may be used instead of AND A.

2. The sequence LD A.E .JP p. DEST

has unpredictable results, since LD does not affect the flags. Either of the following sequences forces a jump if register E is positive:

or

LD A.E AND A .JP P.DEST SUB A OR E JP P.DEST

3. The instruction CP 25H sets the Carry flag as follows:

• Carry

=

I if the contents of A are between 00 and 2416.

. Carry

=

0 if the contents of A are between 2516 and FF 16.

The Carry flag is set if A contains an unsigned number less than the other operand and is cleared if A contains an unsigned number greater than or equal to the other operand.

If you want to set Carry if the accumulator contains 2516, use CP 26H instead ofCP 25H. That is, we have

CP 25H

JR C.LESS JBRANCH IF (A) LESS THAN 25 or

CP 26H

JR C.LESSEQ JBRANCH IF (A) 25 OR LESS 4. the sequence

RLA

JP P.DONE

has unpredictable results, since RLA does not affect the Sign flag. The correct sequence (producing a circular shift that affects the flags) is

ADC A.A ;SHIFT CIRCULAR. SETTING FLAGS .JP P. DONE

CHAPTER 3 COMMON PROGRAMMING ERRORS

145

Of course, you can also use the somewhat slower RLA

RLA JR C,DONE

This approach allows a relative branch.

5. The sequence INC B

JR C,OVRFLW

has unpredictable results, since INC does not affect the Carry flag. The correct sequence is

INC B

JR Z,OVRFLW

since INC does affect the Zero flag when it is applied to an 8-bit operand.

6. The sequence DEC B

JR C,OVRFLW

has unpredictable results, since DEC does not affect the Carry flag. If B cannot contain a number larger than 8016 (unsigned), you can use

DEC B

JP M,OVRFLW

since DEC does affect the Sign flag (when applied to an 8-bit operand). Note, however, that you will get an erroneous branch if B initially contains 8116.

A longer but more general sequence is INC B

DEC B

JR Z,OVRFLW DEC B

,TEST REGISTER B

,BRANCH IF B CONTAINS ZERO

Note that register B will contain 0 (not FF16) if the program branches to address OVRFLW.

7. The sequence DEC BC JR NZ,LOOP

has unpredictable results, since DEC does not affect any flags when it is applied to a 16-bit operand. The correct sequence for decrementing and testing a 16-bit counter in register pair BC is

DEC BC LD A,C OR B JR NZ,LOOP

,CHECK IF BC HAS ANY 1 BITS

,BC CANNOT BE ZERO IF ANY BITS ARE 1

146

Z80 ASSEMBLY LANGUAGE SUBROUTINES

This sequence affects the accumulator and all the flags, including Carry (which OR clears).

8. AND A or OR A clears Carry without affecting any registers. To clear Carry without affecting the other flags, use the sequence

SCF CCF :FIRST SET THE CARRY FLAG :THEN CLEAR IT BY COMPLEMENTING

9. SUB A or XOR A clears the accumulator, the Carry flag, and the Sign flag (and sets the Zero flag). To clear the accumulator without affecting the flags, use LD A,O.

10. The sequence ADD HL,DE JR Z,BNDRY

has unpredictable results, since ADD HL does not affect the Zero flag. To force a branch if the sum is 0, you must test HL explicitly as follows:

ADD HL,DE

LD A,H :TEST HAND L FOR ZERO

OR L JR Z,BNDRY An alternative is

AND A ADC HL,DE JR Z,BNDRY

:CLEAR CARRY Unlike ADD HL, ADC HL affects the Zero flag.

Im Dokument Assembly Language Subroutines (Seite 155-159)