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

You must log in to answer this question.

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