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 a
afterand #imm
because the carry flag is already cleared.