Show your Z80 prowess!

Discussion in 'Technical Discussion' started by Dr. Ivo, Apr 4, 2007.

  1. Dr. Ivo

    Dr. Ivo

    Professional Reverse Engineer Tech Member
    I need a Z80 expert to tell me exactly what the following code does. It's short and simple, and just involves a little bit of math. However, I picked up Z80 exactly a few hours ago, and I can't seem to make sense of the how the flags work in relation to the mathematical operators. The comments that appear below may, of course, be very wrong.

    Here's the challenge:

    Code (Text):
    1. 2a12  67        ld    h,a                 ; h = a
    2. 2a13  5f        ld    e,a                  ; e = a
    3. 2a14  2e00    ld      l,#00           ; l = 00
    4. 2a16  55        ld    d,l                   ;d = 00
    5. 2a17  0e08    ld      c,#08          ; c  = 08
    6. ; loop start
    7. 2a19  29        add  hl,hl             ; hl += hl
    8. 2a1a  d21e2a    jp    nc,#2a1e     ; jump on overflow????
    9. 2a1d  19        add  hl,de             ; hl += de
    10. 2a1e  0d        dec  c                   ; c--
    11. 2a1f  c2192a    jp    nz,#2a19      ; jump to loop start if c is not 1
    12. 2a22  c9        ret
    This code is taking the distance between two characters on screen and turning them into a destination coordinate. The return value of this function is whatever is in HL -- and will be interpreted as XXYY coordinates. Weird huh?

    I can't imagine why they are perfoming an add hl, hl eight times in a row!

    So, who here is smart enough with the Z80 to tell me what the mathematical significance of this peice of code is?
     
  2. drx

    drx

    mfw Researcher
    2,244
    320
    63
    :rolleyes:
    It's a neat subroutine to compute a square of a given integer.

    Basically, HL = A^2.

    Also, the 'jp nc' is Jump when No Carry. I assume you know what carry is. When you add two bytes: 128+128, the result is 0, and the carry is 1.

    If you need a detailed description of how this works, let me know.
     
  3. Dr. Ivo

    Dr. Ivo

    Professional Reverse Engineer Tech Member
    The entire routine just squares an integer? It seems like it multiplies it by 8, to me.


    What is the significance of having the loop run 8 times?


    My understanding was this:

    If the value of A, coming into the function is, say, 5. It'll set:

    HL = 0500
    DE = 0005
    BC = 0008

    Then proceed to add HL to itself 8 times, since there is no carry -- leaving HL = 2D00. If the highbyte of HL overflows the value, then it'll add DE to HL.
     
  4. drx

    drx

    mfw Researcher
    2,244
    320
    63
    :rolleyes:
    ok, I'll break it down for you:

    add hl,hl

    is the same as

    hl = hl + hl

    which is the same as

    hl = hl * 2

    which is the same as shifting the value of HL by one bit to the left (binary arithmetic).

    So after doing this you shift the higher byte of HL out of HL :P That's right, it's gone. So why was it there? To serve as a helpful byte for telling when to add DE (A) and when not.

    what the loop does is:

    Code (Text):
    1. for (counter = 8; counter > 0; c--) {
    2.   HL = HL << 1
    3.   if (CARRY) HL += A;
    4. }
    I think it's similar to the Horner thing in polynomials.

    Ie. you can represent an integer in binary: 1110 0011 as 1*2^7 + 1*2^6 + 1*2^5 + 1*2^1 + 1*2^0. But you can also represent that as (((1*2+1)*2+1)*2*2*2*2+1)*2+1.

    So what you're doing in each step of the loop is multiply the whole integer by 2 and add 1/0 depending on the binary represantation.

    The same scheme was used here, except for squaring the number.

    I'm sorry if my explanation sucks, I'm tired :P
     
  5. Dr. Ivo

    Dr. Ivo

    Professional Reverse Engineer Tech Member
    Aha!

    Could you tell me what this does, then? It's full of binary math, and I assume it is receiving HL as XXYY coordinates into the playfield grid, and then returning HL as the memory address of the grid location. (#4040 + whatever has been calculated)


    Code (Text):
    1. 202d  f5        push    af
    2. 202e  c5        push    bc
    3. 202f  7d        ld    a,l
    4. 2030  d620    sub    #20
    5. 2032  6f        ld    l,a
    6. 2033  7c        ld    a,h
    7. 2034  d620    sub    #20
    8. 2036  67        ld    h,a
    9. 2037  0600    ld      b,#00
    10. 2039  cb24    sla    h
    11. 203b  cb24    sla    h
    12. 203d  cb24    sla    h
    13. 203f  cb24    sla    h
    14. 2041  cb10    rl      b
    15. 2043  cb24    sla    h
    16. 2045  cb10    rl      b
    17. 2047  4c        ld    c,h
    18. 2048  2600    ld      h,#00
    19. 204a  09        add  hl,bc
    20. 204b  014040    ld    bc,#4040  -- map location
    21. 204e  09        add  hl,bc
    22. 204f  c1        pop  bc
    23. 2050  f1        pop  af
    24. 2051  c9        ret