Comparisons

Optimising comparing numbers

A = 0

A common test is to see if A is 0, so you would expect to use CP 0 to test for it.

Just like setting A to 0 we can compare quicker. In this case, instead of CP 0 we can just use either OR A or AND A instead. Just 1 byte and 3 T-states faster.

FE00CP0A-0 will set Z if A is also 0
A7ANDAAnything AND itself is itself but Z is set if A is 0
B7ORAAnything OR itself is itself but Z is set if A is 0

For example, take this simple routine which writes a NULL terminated string pointed to by HL to the screen of the Sinclair ZX Spectrum:

Print null terminated string at HL to the screen
printStrLDA,(HL)get next byte
CP0check for null
RETZStop when we get a null
RST2print the character
INCHLmove to next character
JRprintStrloop back

The optimisation here is to replace CP 0 with OR A

Print null terminated string at HL to the screen
printStrLDA,(HL)get next byte
ORAcheck for null
RETZStop when we get a null
RST2print the character
INCHLmove to next character
JRprintStrloop back

A = 1

Comparing A to 1 can also be done using DEC A instead of CP 1. By decrementing A, the Z flag will be set if A is now 0. Like above its faster and 1 byte, but it also alters A, so it's not really of any use unless you don't care about the value of A after the test.

FE01CP1A-1 will set Z if A is also 1
3DDECAA=A-1, Z is set if A is now 0

Internally, CP 1 just does A-1 but discards the result which is why DEC A works in this instance.

Compare number

With CP it's easy to test for less than (<), equals (=), not equals (!=) or greater-than-equals (>=) because of how the C and Z flags are used:

CP15test A against 15
RETCReturn if A < 15
RETNCReturn if A >= 15
RETZReturn if A = 15
RETNZReturn if A != 15

The following shows how to get the other two tests, Less-Than-Equals (<=) and Greater-Than(>):

A <= n

This is a simple one. As CP tests against A-n then if A=N then Z is set but if A < n then C is set.

CP15test for A<=15
RETCReturn if A<15
RETZReturn if A=15

To optimise this we should test against n+1 instead. Doing this means we can just use the Carry flag as it would be set when A < n+1:

CP15+1test for A<16
RETCReturn if A<16

A > n

This is the opposite problem. Here Carry is clear when A>=n, so to get A>n we first need to test for equals using the Z flag and if that's not set then check for the Carry flag to be clear:

CP15test for A>15
JRZ, skipSkip if A=15
RETNCReturn if A>=15
skipContinue as A was <= 15

Like the previous example, this can be optimised simply by adding 1 and then testing for A >= (n+1) instead:

CP15+1test for A>=16
RETNCReturn if A>=16

Wasteful use of CP

It's easy to forget that some instructions set the flags based on the result so frequently you do not need to use CP to test for a condition when the result is already known:

Here we check for bit 1 of A is set and if it is we exit the subroutine:

E601AND1A=A AND 0x01
FE01CP1Is A set to 1
C8RETZReturn is A is now 1

Here the CP isn't required as AND will set Z if A=0, so we can remove the CP and use NZ instead saving 2 bytes:

E601AND1A=A AND 0x01
C8RETNZReturn as A is now 1

Testing bits

Testing Bit 0 of A

The standard method of testing if bit 0 of A is set is to use BIT 0,A:

CB47BIT0,ATest if BIT 0 is set
C8RETNZReturn as bit 0 of A was set

If we don't need A afterwards then we can optimise this by using a right shift instead:

1FRRAShift A right 1 bit, C=original bit 0
C8RETCReturn as bit 0 of A was set

This works as we just shifted bit 0 into the Carry Flag and we save an additional byte in the process.

Using RRA would be faster & saves 1 byte, but it destroys A. If you need to keep A intact then keep the BIT instruction.

Testing Bit 7 of A

Just like testing bit 0, with bit 7 we can do the same but shifting right instead. So rather than using BIT 7,A like:

CB7FBIT7,ATest if BIT 7 is set
C8RETNZReturn as bit 7 of A was set

We can just use RLA and test the Carry flag:

17RLAShift A left 1 bit, C=original bit 7
C8RETCReturn as bit 7 of A was set

The downside of this is it destroys the contents of A.


Last modified November 14, 2021: Rename tips to optimization (8743ec0)