9

Programming the Z80 (3rd edition) has the following code sample (section 3 p.135) for division of a 16-bit dividend by an 8-bit divisor returning an 8-bit quotient in L and an 8 bit remainder in H:

DIV168  LD     A, (DVSAD)  LOAD DIVISOR
        LD     D, A        INTO D
        LD     E, 0
        LD     HL, (DVDAD) LOAD 16-BIT DIVIDEND
        LD     B, 8        INITIALIZE COUNTER
DIV     XOR    A           CLEAR C BIT
        SBC    HL, DE      DIVIDEND - DIVISOR
        INC    HL          QUOTIENT = QUOTIENT + 1
        JP     P, NOADD    TEST IF REMAINDER
                           POSITIVE
        ADD    HL, DE      RESTORE IF NECESSARY
        DEC    HL          QUOTIENT = QUOTIENT - 1

NOADD   ADD    HL, HL      SHIFT DIVIDEND LEFT
        DJNZ   DIV         LOOP UNTIL B = 0
        RET

For 6/2 this seems to return 6/2 = 2 remainder 2. I think this is because it ends on a shift (ADD HL, HL) when it should end with a subtract/test.

Moving ADD HL, HL inside the loop just before XOR A seems to fix the program.

My question: does the original code have a bug and is my proposed fix valid? Or is there another/better way to modify the program?

8
  • How did you test this?
    – Raffzahn
    Commented Nov 14 at 18:15
  • @Raffzahn I manually evaluated the code pen and paper style. I also played with a Python conversion and ran it on this emulator github.com/redcode/Z80
    – Dexter CD
    Commented Nov 14 at 18:28
  • The quotient is not guaranteed to fit in 8 bits. What is supposed to happen if you divide 0xFFFF by 1?
    – Leo B.
    Commented Nov 14 at 19:13
  • @LeoB. It's an example from a book intended to teach the very basics, not exactly a perfect implementation.
    – Raffzahn
    Commented Nov 14 at 19:26
  • 2
    @LeoB. x86 has an equivalent functionality in DIV, which divides two concatenated registers by a single register. If the quotient overflows, it raises a division error (DE), which is (mis)interpreted by many systems as solely a divide-by-0 condition. The instruction is ideal for multi-word division, the classic algorithm for which needs such a double-word division primitive but ensures there is no overflow.
    – Sneftel
    Commented Nov 16 at 18:47

1 Answer 1

11

I own a paper copy of SYBEX's German translation of Zaks's book: Programmierung des Z80. It was published in 1985, the translator was Bernd Ploss. It contains the following version of the sample code from the question, which (based on cursory inspection) appears to have the functional bug fixed, but uses an erroneous comment for DEC HL:

DIV168   LD   A,(DVSAD)   Lade Divisor
         LD   D,A         nach D
         LD   E,0
         LD   HL,(DVDAD)  Lade 16-Bit-Dividend
         LD   B,9         Initialisiere Zähler
         JP   REIN        Springe zu REIN
DIV      ADD  HL,HL       Schiebe Dividend links
REIN     XOR  A           Lösche Bit C
         SBC  HL,DE       Dividend-Divisor
         INC  HL          Quotient=Quotient+1
         JP   P,NOADD     Teste, ob Rest positiv
         ADD  HL,DE       Stelle wieder her, 
                          wenn nötig
         DEC  HL          Quotient=Quotient+1
NOADD    DJNZ DIV         Schleife, bis B=1
         RET

I have no information which original English language edition served as the basis for the German translation. To my limited knowledge, fixing bugs is not part of the normal translation process for books, and there is no translator's note at the start of the book alerting readers to deviations from, or enhancements to, the original publication.

3
  • 1
    Perhaps they started work on a 4th edition but never released it but the translation was based on that.
    – Dexter CD
    Commented Nov 15 at 23:03
  • 2
    @Dexter CD That was my guess as well, but I did not want to speculate unnecessarily.
    – njuffa
    Commented Nov 15 at 23:07
  • 3
    Errata from the third edition was probably available at the time the translation was done. Commented Nov 16 at 15:01

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .