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 start: 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 ret 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 rla 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 rra rra 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 ret 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:

and aafterand #immbecause the carry flag is already cleared.