; *************************************************************************** ; Calculates the actual screen address for a character in BC (row,col) ; returning that address in HL. ; ; Author: Peter Mount, Area51.dev & Contributors ; URL: https://area51.dev/sinclair/asm/screen/getcharaddr/ ; *************************************************************************** ; ; Although the memory layout for the spectrum screen seems weird, ; it's actually pretty logical. You can tell this weirdness is down to how ; the ULA works internally with the way the addressing is mapped, as shown ; at https://area51.dev/sinclair/spectrum/screen/file/ ; ; Address format: ; H L ; 010rrnnn rrrccccc where r=row, ; c=column, ; n=row in the character definition. ; ; To calculate the address of a character: ; High byte = &40 or (row and &18) ; Low byte = (row<<5) or column ; ; That would then be the top byte of the character. ; ; To get the next byte in the character just increment the high byte ; (e.g. n=1) & so on for the next 7 bytes. ; ; To get the next character's address then simply increment the low byte. ; Be careful however when wrapping around the end of the line as, after ; the first 8 lines the address will fail. ; ; Ideally you should calculate the address again at the start of each line. ; ; This might explain why the original spectrum editor was 8 lines long, as you ; only needed to set the high byte to the 8-line block in memory and set the ; low byte to the offset in the line being edited to get that characters ; screen address. ; ; On Entry: ; BC b=row, c=col in Spectrum 32x24 characters ; ; On Exit: ; HL address of top row if character definition in screen ; BC unchanged ; A undefined ; getSpectrumCharPos: ; Get Spectrum char pos (bc) into HL for physical screen address ld a, b ; first calculate high byte - get row and &18 ; Mask bits 4 & 5 from row or &40 ; set bit 6, this gives us the upper memory address ld h, a ; Set H ld a, b ; get row add a ; Shift left 5 to form low address add a ; use add not srl as this saves 1 byte and half the t-states add a ; per shift, especially as we don't need to worry about carry flag add a add a ; HA is now the address of the start of line or c ; Add column value ld l, a ; HL now address of top row of character ret