I originally posted this question on stackoverflow, but I wrote a little program that converts coordinates stored in the b and c registers of the z80 into their corresponding memory address for the ZX Spectrum screen bitmap. Here it is:

org $8000    

   ld b, $0f            ;0-32  X
   ld c, $08            ;0-255  Y
   call convert_xy
   ld (hl), $ff
   ;this shows where the pixels are supposed to end up
   ld a, $ff
   ld ($402f), a        ;the subroutine is supposed to produce this value in hl
convert_xy:             ;convert (x,y) locations to bitmap memory locations, answer is stored in hl
    ld a,c              ;y first
    and %00111000       ;let's look at y3-y5 first
    and a               ;clear carry flag
    rla                 ;move over to end of low byte
    ld l,a              ;move results to low byte storage register
    ld a,c              ;look at the rest of y
    and %11000000       ;look at y7 and 6
    and a
    rra                 ;move over
    ld d,a              ;temporary storage
    ld a,c
    or %01000000        ;base address ($4000)
    or d                ;done
    ld h,a              ;move to results register
    ld a,b              ;x now
    and %00011111
    or l
    ld l,a              ;store result in l

The portion of the code containing the x coordinate works just fine but the part of the subroutine concerning the y coordinate acts strange when any value over 7 is converted.

For example, when I try to convert y = $08, the byte loaded onto the screen suddenly skips and ends up in the middle of the screen (while 0-7 neatly moved down the pixels on screen one pixel at a time). Values over $10 disappear from the screen entirely. What is going on? Thank you.

EDIT: Here is the way that the coordinates are encoded into the memory address:

enter image description here

  • Could you add some sort of pseudo-code/formula of what calculation you're trying to perform on y? Use Edit link to edit your question.
    – tum_
    Jul 17, 2021 at 18:18
  • 2
    You don't need the and a after and #imm because the carry flag is already cleared. Jul 18, 2021 at 12:48

1 Answer 1


The code could look like this:

0000   06 0F          LD   b,$0f         ; 0-31  X
0002   0E 08          LD   c,$08         ; 0-191 Y
0004   CD 0A 00       CALL convert_xy   
0007   36 FF          LD   (hl),$ff      ; write the pixels
0009   76             HALT      

000A            convert_xy:    ; convert (x,y) in BC to memory address in HL
000A                           ; assuming arguments are always in valid range

000A   79             LD   a,c       ; getting Y position bits [5:3] ...
000B   07             RLCA           ; adjust it for the address lower byte's
000C   07             RLCA           ; bits [7:5]
000D   E6 E0          AND  $e0       ; mask out the garbage
000F   B0             OR   b         ; mix in the X coordinate
0010   6F             LD   l,a       ; this is final result for address low byte

0011   79             LD   a,c       ; back to Y
0012   E6 07          AND  $7        ; bits Y[2:0] are already in place
0014   F6 40          OR   $40       ; make it $4000 base
0016   67             LD   h,a       ; intermediate state is set to H
0017   79             LD   a,c   
0018   0F             RRCA           ; moving bits Y[7:6] to close the gap
0019   0F             RRCA           ; that was taken by bits Y[5:3] before
001A   0F             RRCA      
001B   E6 18          AND  $18       ; mask out the garbage
001D   B4             OR   h         ; join with temporary in H
001E   67             LD   h,a       ; this is final address high byte
001F   C9             RET      

The result looks ok in online simulator.

Your mistake is to stash the moved bits [7:6] into register D, and then loading A with the original Y coordinate and or'ing it all together with previously masked and moved bits.

  • 1
    Yep, that was my mistake, it seems that adding an AND to target the first three bits after reloading c into a fixed it.
    – Keolai
    Jul 17, 2021 at 20:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.