<< Previous Message Main Index Next Message >>
<< Previous Message in Thread This Month Next Message in Thread >>
Date   : Tue, 15 May 1990 08:00:17 GMT
From   : eru!luth!sunic!mcsun!hp4nl!kunivv1!root@BLOOM-BEACON.MIT.EDU (Privileged Account)
Subject: a<b on Z80

wittig@gmdzi.UUCP (Georg Wittig) writes:

>How to write a signed compare of two 16 bit integers in Z80 assembler? The
>obvious solution doesn't work:

>   [deleted]

>The only compact and correct solution I could find was the following one:

>   LD      HL,a
>   LD      DE,b
>   AND     A
>   SBC     HL,DE
>   JP      PO,LABEL
>   JP      P,IS_LESS
>   JP      IS_GREATER_OR_EQUAL
>LABEL:     JP      P,IS_GREATER_OR_EQUAL
>IS_LESS:...

>But this one looks very ugly to me. Does someone know of a shorter and/or
>faster solution?

Let's see. The easiest solution I could think of was something like this:

       LD      HL,a
       LD      DE,b

       ;Remove 8000H bias from signed numbers

       LD      BC,8000H
       ADD     HL,BC
       EX      DE,HL
       ADD     HL,BC
       EX      DE,HL

       ;Now we can do an unsigned compare

       AND     A                       ;Clear carry
       SBC     HL,DE
       
DONE:  ;Carry flag set if a<b
       ;Zero flag set if a=b
               
This removes the 8000H bias on signed numbers to make them comparable as
unsigned numbers. However, it is not the shortest/fastest one, and
clobbers BC.

A little thought reveals the removing the bias is not needed if both
numbers have the same sign. And luckily, if they don't, we do already
know the answer (or can find out easily). This leads to

       LD      HL,a
       LD      DE,b

       ;Test signs

       LD      A,H
       XOR     D
       JP      M,DIFSGN

       ;Equal signs, do an unsigned compare (carry already clear)

       SBC     HL,DE

       JR      DONE

DIFSGN:        ;Different signs, set up the carry (zero already clear)

       LD      A,H
       RLCA                    ;Does not modify zero flag

DONE:  ;Carry flag set if a<b
       ;Zero flag set if a=b
               
But this still does not satisfy me. However, we can employ a trick to
get the carry and zero flags right in case of different signs. If HL has
the negative signed number, it has the greater unsigned number, and the
unsigned subtraction will thus result in a carry set the wrong way.
The same thing happens when DE has the negative signed number. Thus,
in the case of different signs, we just have to reverse the operands to
the compare to get everything right. Or:

       LD      HL,a
       LD      DE,b

       ;Test signs

       LD      A,H
       XOR     D
       JP      P,EQUSGN

       ;Different signs, have to reverse the operands

       EX      DE,HL

EQUSGN:        ;We can not do an unsigned compare (carry already clear)

       SBC     HL,DE

DONE:  ;Carry flag set if a<b
       ;Zero flag set if a=b
               
This is the best I could think of; it uses only 5 instructions for the
actual compare (8 bytes). If anyone knows better, please mail (or post).
--
Luc Rooijakkers                                 Internet: lwj@cs.kun.nl
Faculty of Mathematics and Computer Science     UUCP: uunet!cs.kun.nl!lwj
University of Nijmegen, the Netherlands         tel. +3180612271

<< Previous Message Main Index Next Message >>
<< Previous Message in Thread This Month Next Message in Thread >>