Diferencias
Muestra las diferencias entre dos versiones de la página.
Ambos lados, revisión anterior Revisión previa Próxima revisión | Revisión previa | ||
cursos:ensamblador:gfx2_direccionamiento [19-01-2024 16:46] – [Optimizando la lectura a través de tablas] sromero | cursos:ensamblador:gfx2_direccionamiento [21-01-2024 17:22] (actual) – [Optimizaciones para Get_Pixel_Offset_HR] sromero | ||
---|---|---|---|
Línea 168: | Línea 168: | ||
; calcular dir_atributo como " | ; calcular dir_atributo como " | ||
ld h, 0 | ld h, 0 | ||
- | ld l, b | + | ld l, b ; HL = " |
- | add hl, hl ; HL = HL*2 | + | add hl, hl |
- | add hl, hl ; HL = HL*4 | + | add hl, hl |
- | add hl, hl ; HL = HL*8 | + | add hl, hl |
- | add hl, hl ; HL = HL*16 | + | add hl, hl |
- | add hl, hl ; HL = HL*32 | + | add hl, hl |
ld d, 0 | ld d, 0 | ||
- | ld e, c | + | ld e, c ; DE = " |
- | add hl, de ; HL = fila*32 + columna | + | add hl, de |
- | ld de, 22528 ; Direccion de inicio de atributos | + | ld de, 22528 |
- | add hl, de ; HL = 22528 + fila*32 + columna | + | add hl, de |
ret | ret | ||
</ | </ | ||
Línea 226: | Línea 226: | ||
; | ; | ||
Get_Attribute_Offset_LR: | Get_Attribute_Offset_LR: | ||
- | ld a, b ; Ponemos en A la fila (000FFFFFb) | + | ld a, b ; Ponemos en A la fila (000FFFFFb) |
rrca | rrca | ||
rrca | rrca | ||
- | rrca | + | rrca |
- | and 3 | + | and %00000011 |
- | | + | |
- | add a, $58 ; Ponemos los bits 15-10 como 010110b | + | add a, %01011000 |
- | ld h, a ; Lo cargamos en el byte alto de HL | + | ld h, a ; Lo cargamos en el byte alto de HL |
- | ld a, b ; Recuperamos de nuevo en A la FILA | + | ld a, b ; Recuperamos de nuevo en A la FILA |
- | and 7 | + | and %00000111 |
rrca | rrca | ||
- | rrca | + | rrca |
- | rrca | + | rrca |
- | add a, c | + | add a, c |
- | ld l, a ; Lo colocamos en L | + | ld l, a ; Lo colocamos en L |
- | ret ; HL = 010110FFFFFCCCCCb | + | ret ; HL = %010110FFFFFCCCCC |
</ | </ | ||
Línea 255: | Línea 255: | ||
call Get_Attribute_Offset_LR | call Get_Attribute_Offset_LR | ||
- | ld a, 85 | + | ld a, 85 |
- | ld (hl), a | + | ld (hl), a |
</ | </ | ||
Línea 268: | Línea 268: | ||
srl b | srl b | ||
srl b | srl b | ||
- | srl b ; B = B/8 -> Ahora B es FILA | + | srl b ; B = B/8 -> Ahora B es FILA |
srl c | srl c | ||
srl c | srl c | ||
- | srl c ; C = C/8 -> Ahora C es COLUMNA | + | srl c ; C = C/8 -> Ahora C es COLUMNA |
</ | </ | ||
Línea 289: | Línea 289: | ||
srl b | srl b | ||
srl b | srl b | ||
- | srl b ; B = B/8 -> Ahora B es FILA | + | srl b ; B = B/8 -> Ahora B es FILA |
srl c | srl c | ||
srl c | srl c | ||
- | srl c ; C = C/8 -> Ahora C es COLUMNA | + | srl c ; C = C/8 -> Ahora C es COLUMNA |
ld a, b | ld a, b | ||
rrca | rrca | ||
rrca | rrca | ||
- | rrca | + | rrca |
- | and 3 | + | and %00000011 |
- | | + | |
- | + | add a, %01011000 | |
- | add a, $58 ; Ponemos los bits 15-10 como 010110b | + | ld h, a ; Lo cargamos en el byte alto de HL |
- | ld h, a ; Lo cargamos en el byte alto de HL | + | ld a, b ; Recuperamos de nuevo en A la FILA |
- | ld a, b ; Recuperamos de nuevo en A la FILA | + | and %00000011 |
- | and 7 | + | |
rrca | rrca | ||
- | rrca | + | rrca |
- | rrca | + | rrca |
- | add a, c | + | add a, c |
- | ld l, a ; Lo colocamos en L | + | ld l, a ; Lo colocamos en L |
- | ret ; HL = 010110FFFFFCCCCCb | + | ret ; HL = 010110FFFFFCCCCCb |
</ | </ | ||
Línea 332: | Línea 331: | ||
; | ; | ||
Get_Attribute_Coordinates_LR: | Get_Attribute_Coordinates_LR: | ||
- | | + | ; Descomponemos HL = 010110FF FFFCCCCCb |
- | ld a, h ; A = 010110FFb | + | ld a, h ; A = 010110FFb |
- | and 3 | + | and %00000011 |
rlca | rlca | ||
rlca | rlca | ||
- | rlca | + | rlca |
- | ld b, a ; B = 000FF000b | + | ld b, a ; B = 000FF000b |
ld a, l | ld a, l | ||
- | and 224 ; Nos quedamos con los 3 bits mas altos | + | and %11100000 |
rlca | rlca | ||
rlca | rlca | ||
- | rlca | + | rlca |
- | or b | + | or b |
- | ld b, a ; B = FILA | + | ld b, a ; B = FILA |
ld a, l | ld a, l | ||
- | and 31 ; Nos quedamos con los 5 bits mas bajos | + | and %00011111 |
- | ld c, a ; C = COLUMNA | + | ld c, a ; C = COLUMNA |
ret | ret | ||
Línea 369: | Línea 368: | ||
; | ; | ||
Get_Attribute_Coordinates_HR: | Get_Attribute_Coordinates_HR: | ||
- | ; Descomponemos HL = 010110FF FFFCCCCCb | + | ; Descomponemos HL = 010110FF FFFCCCCCb |
- | ld a, h ; A = 010110FFb | + | ld a, h ; A = 010110FFb |
- | and 3 ; A = bits 0, 1 de HL = 2 bits altos de F, CF=0 | + | and 3 ; A = bits 0, 1 de HL = 2 bits altos de F, CF=0 |
rlca | rlca | ||
rlca | rlca | ||
- | rlca | + | rlca |
- | ld b, a ; B = 000FF000b | + | ld b, a ; B = 000FF000b |
ld a, l | ld a, l | ||
- | and 224 ; Nos quedamos con los 3 bits mas altos | + | and %11100000 |
rlca | rlca | ||
rlca | rlca | ||
- | rlca | + | rlca |
- | or b | + | or b |
- | ld b, a ; B = FILA | + | ld b, a ; B = FILA |
ld a, l | ld a, l | ||
- | and 31 ; Nos quedamos con los 5 bits mas bajos | + | and %00011111 |
- | ld c, a ; C = COLUMNA | + | ld c, a ; C = COLUMNA |
sla c | sla c | ||
sla c | sla c | ||
- | sla c ; C = C*8 | + | sla c ; C = C*8 |
sla b | sla b | ||
sla b | sla b | ||
- | sla b ; B = B*8 | + | sla b ; B = B*8 |
ret | ret | ||
Línea 409: | Línea 408: | ||
<code z80> | <code z80> | ||
Atributo_derecha: | Atributo_derecha: | ||
- | inc hl ; HL = HL + 1 | + | inc hl |
Atributo_izquierda: | Atributo_izquierda: | ||
- | dec hl ; HL = HL - 1 | + | dec hl |
Atributo_abajo: | Atributo_abajo: | ||
ld de, 32 | ld de, 32 | ||
- | add hl, de ; HL = HL + 32 | + | add hl, de |
Atributo_arriba: | Atributo_arriba: | ||
ld de, -32 | ld de, -32 | ||
- | add hl, de ; HL = HL - 32 | + | add hl, de |
</ | </ | ||
Línea 427: | Línea 426: | ||
<code z80> | <code z80> | ||
Atributo_abajo_sin_usar_DE_2: | Atributo_abajo_sin_usar_DE_2: | ||
- | ld a, l | + | ld a, l ; A = L |
- | | + | |
- | ld l, a | + | ld l, a ; Guardamos en L (L = L+32) |
jr nc, attrab_noinc | jr nc, attrab_noinc | ||
inc h | inc h | ||
- | attrab_noinc: | + | attrab_noinc: |
Atributo_arriba_sin_usar_DE: | Atributo_arriba_sin_usar_DE: | ||
- | ld a, l | + | ld a, l ; A = L |
- | sub 32 ; Restamos A = A - 32 . El Carry Flag se ve afectado. | + | sub 32 |
- | ld l, a | + | ld l, a ; Guardamos en L (L = L-32) |
jr nc, attrab_nodec | jr nc, attrab_nodec | ||
dec h | dec h | ||
- | attrab_nodec: | + | attrab_nodec: |
</ | </ | ||
Línea 455: | Línea 454: | ||
<code z80> | <code z80> | ||
- | ld a, 0 | + | ld a, 0 ; Ponemos A a cero, no podemos usar un "xor a" |
- | ; o un "or a" porque afectariamos al Carry Flag. | + | |
- | | + | |
- | ld h, a | + | ld h, a ; H = H + CarryFlag |
- | ; Ahora HL = (H+CF)*256 + (L+32) = HL + 32 | + | |
</ | </ | ||
Línea 577: | Línea 576: | ||
; | ; | ||
Get_Line_Offset_LR: | Get_Line_Offset_LR: | ||
- | ld a, b | + | ld a, b ; A = B, para extraer los bits de tercio |
- | and $18 ; A = A and 00011000b | + | and %00011000 |
- | ; A = estado de bits de TERCIO desde FILA | + | |
- | add a, $40 | + | add a, %01000000 |
- | ld h, a | + | ld h, a ; Ya tenemos la parte alta calculada |
- | ; H = 010TT000 | + | |
- | ld a, b | + | ld a, b ; Ahora calculamos la parte baja |
- | and 7 ; Nos quedamos con los bits más bajos de FILA | + | and %00000111 |
- | ; que coinciden con FT (Fila dentro del tercio) | + | |
- | rrca ; Ahora A = 00000NNNb | + | rrca |
- | rrca ; Desplazamos A 3 veces | + | rrca |
- | rrca ; A = NNN00000b | + | rrca |
- | ld l, a | + | ld l, a ; Lo cargamos en la parte baja de la direccion |
- | ret | + | ret ; HL = 010TT000NNN00000b |
</ | </ | ||
Línea 629: | Línea 628: | ||
; | ; | ||
Get_Char_Offset_LR: | Get_Char_Offset_LR: | ||
- | ld a, b | + | ld a, b ; A = B, para extraer los bits de tercio |
- | and $18 ; A = A and 00011000b | + | and %00011000 |
- | ; A = estado de bits de TERCIO desde FILA | + | |
- | add a, $40 | + | add a, %01000000 |
- | ld h, a | + | ld h, a ; Ya tenemos la parte alta calculada |
- | ; H = 010TT000 | + | |
- | ld a, b | + | ld a, b ; Ahora calculamos la parte baja |
- | and 7 ; Nos quedamos con los bits más bajos de FILA | + | and %00000111 |
- | ; que coinciden con FT (Fila dentro del tercio) | + | |
- | rrca ; Ahora A = 00000NNNb | + | rrca |
- | rrca ; Desplazamos A 3 veces a la derecha | + | rrca |
- | rrca ; A = NNN00000b | + | rrca |
- | add a, c ; Sumamos COLUMNA -> A = NNNCCCCCb | + | add a, c |
- | ld l, a | + | ld l, a ; Lo cargamos en la parte baja de la direccion |
- | ret | + | ret ; HL = 010TT000NNNCCCCCb |
</ | </ | ||
Línea 660: | Línea 659: | ||
srl b | srl b | ||
srl b | srl b | ||
- | srl b | + | srl b ; B = B/8 -> Ahora B es FILA |
srl c | srl c | ||
srl c | srl c | ||
- | srl c | + | srl c ; C = C/8 -> Ahora C es COLUMNA |
- | (...) | + | (...) ; Resto de la rutina Get_Char_Offset_LR |
ret | ret | ||
</ | </ | ||
Línea 688: | Línea 687: | ||
; HL = 010TT000 NNNCCCCCb -> | ; HL = 010TT000 NNNCCCCCb -> | ||
; Fila = 000TTNNNb y Columna = 000CCCCCb | ; Fila = 000TTNNNb y Columna = 000CCCCCb | ||
- | ; Calculo de la fila: | ||
- | ld a, h ; A = H, para extraer los bits de tercio | ||
- | and $18 ; A = 000TT000b | ||
- | ld b, a ; B = A = 000TT000b | ||
- | | + | ; Calculo de la fila: |
- | and $e0 ; A = A and 11100000b = NNN00000b | + | ld a, h ; A = H, para extraer los bits de tercio |
- | rlc a | + | and %00011000 |
+ | ld b, a ; B = A = 000TT000b | ||
+ | |||
+ | | ||
+ | and %0b11100000 | ||
+ | rlc a ; Rotamos A 3 veces a la izquierda | ||
rlc a | rlc a | ||
- | rlc a | + | rlc a ; A = 00000NNNb |
- | or b ; A = A or b = 000TTNNNb | + | or b |
- | ld b, a | + | ld b, a ; B = A = 000TTNNNb |
- | | + | ; Calculo de la columna: |
- | ld a, l | + | ld a, l ; A = L, para extraer los bits de columna |
- | and $1f ; Nos quedamos con los ultimos 5 bits de L | + | and %00011111 |
- | ld c, a | + | ld c, a ; C = Columna |
- | ret ; HL = 010TT000NNNCCCCCb | + | |
</ | </ | ||
Línea 713: | Línea 713: | ||
sla c | sla c | ||
sla c | sla c | ||
- | sla c ; C = C*8 | + | sla c ; C = C*8 |
sla b | sla b | ||
sla b | sla b | ||
- | sla b ; B = B*8 | + | sla b ; B = B*8 |
</ | </ | ||
Línea 733: | Línea 733: | ||
<code z80> | <code z80> | ||
Scanline_Arriba_HL: | Scanline_Arriba_HL: | ||
- | dec h ; H = H - 1 (HL = HL-255) | + | dec h ; H = H - 1 (HL = HL-255) |
Scanline_Abajo_HL: | Scanline_Abajo_HL: | ||
- | inc h ; H = H + 1 (HL = HL-255) | + | inc h ; H = H + 1 (HL = HL-255) |
</ | </ | ||
Línea 752: | Línea 752: | ||
<code z80> | <code z80> | ||
Caracter_Derecha_HL: | Caracter_Derecha_HL: | ||
- | inc hl ; HL = HL + 1 | + | inc hl |
Caracter_Izquierda_HL: | Caracter_Izquierda_HL: | ||
- | dec hl ; HL = HL - 1 | + | dec hl |
</ | </ | ||
Línea 774: | Línea 774: | ||
<code z80> | <code z80> | ||
- | | + | Caracter_Abajo_HL: |
- | add a, 32 ; incrementar " | + | |
- | ld l, a | + | add a, %00100000 |
- | jr nc, no_ajustar_H_abajob | + | ld l, a |
- | ld a, h | + | jr nc, no_ajustar_H_abajob |
- | add a, 8 | + | ld a, h |
- | ld h, a | + | add a, %00001000 |
+ | ld h, a | ||
no_ajustar_H_abajob | no_ajustar_H_abajob | ||
- | | + | |
</ | </ | ||
Línea 788: | Línea 789: | ||
<code z80> | <code z80> | ||
- | ld a, l ; Cargamos L en A | ||
- | and 224 ; A = A and 11100000b | ||
- | jr nz, no_ajustar_h_arribab | ||
- | ld a, h ; Si es cero, ajustamos tercio (-1) | ||
- | sub 8 ; Decrementamos TT | ||
- | ld h, a | ||
- | no_ajustar_h_arribab: | ||
- | ld a, l ; Decrementar NNN | ||
- | sub 32 | ||
- | ld l, a ; NNN = NNN-1 | ||
- | </ | ||
- | |||
- | En forma de rutina: | ||
- | |||
- | <code z80> | ||
- | Caracter_Abajo_HL: | ||
- | ld a, l ; Cargamos A en L y le sumamos 32 para | ||
- | add a, 32 ; incrementar " | ||
- | ld l, a ; L = A | ||
- | ret nc ; Si esta suma no produce acarreo, fin | ||
- | ld a, h ; la parte alta sumando 8 a H (TT = TT + 1). | ||
- | add a, 8 ; Ahora NNN=000b y TT se ha incrementado. | ||
- | ld h, a ; H = A | ||
- | ret | ||
- | |||
Caracter_Arriba_HL: | Caracter_Arriba_HL: | ||
ld a, l ; Cargamos L en A | ld a, l ; Cargamos L en A | ||
- | and 224 ; A = A and 11100000b | + | and %11100000 |
jr nz, nofix_h_arribab | jr nz, nofix_h_arribab | ||
ld a, h ; Si es cero, ajustamos tercio (-1) | ld a, h ; Si es cero, ajustamos tercio (-1) | ||
- | sub 8 ; Decrementamos TT | + | sub %00001000 |
ld h, a | ld h, a | ||
nofix_h_arribab: | nofix_h_arribab: | ||
Línea 914: | Línea 890: | ||
\\ | \\ | ||
- | No obstante, recordemos que esta dirección de memoria obtenida hace referencia a 8 píxeles, por lo que necesitamos obtener además la información del número de bit con el que se corresponde nuestro pixel, que podemos extraer del resto de la división entre 8 de la coordenada X (P = X and 7). | + | No obstante, recordemos que esta dirección de memoria obtenida hace referencia a 8 píxeles, por lo que necesitamos obtener además la información del número de bit con el que se corresponde nuestro pixel, que podemos extraer del resto de la división entre 8 de la coordenada X (P = X and %00000111). |
La rutina resultante es similar a la vista en baja resolución con la descomposición de la coordenada Y en el " | La rutina resultante es similar a la vista en baja resolución con la descomposición de la coordenada Y en el " | ||
Línea 931: | Línea 907: | ||
; Calculo de la parte alta de la direccion: | ; Calculo de la parte alta de la direccion: | ||
ld a, b | ld a, b | ||
- | and 7 ; A = 00000SSSb | + | and %00000111 |
- | ld h, a | + | ld h, a ; Lo guardamos en H |
- | ld a, b | + | ld a, b ; Recuperamos de nuevo Y |
rra | rra | ||
rra | rra | ||
- | rra | + | rra ; Rotamos para asi obtener el tercio |
- | and 24 | + | and %00011000 |
- | or h ; H = H or a = 00000SSSb or 000TT000b | + | or h |
- | or 64 ; Mezclamos H con 01000000b (vram) | + | or %01000000 |
- | ld h, a | + | ld h, a ; Establecemos el " |
; Calculo de la parte baja de la direccion: | ; Calculo de la parte baja de la direccion: | ||
- | ld a, c | + | ld a, c ; A = coordenada X |
rra | rra | ||
rra | rra | ||
- | rra | + | rra ; Rotamos para obtener CCCCCb |
- | and 31 | + | and %00011111 |
- | ld l, a | + | ld l, a ; L = 000CCCCCb |
- | ld a, b | + | ld a, b ; Recuperamos de nuevo Y |
- | rla | + | rla ; Rotamos para obtener NNN |
rla | rla | ||
- | and 224 ; A = A and 11100000b | + | and %11100000 |
- | or l ; L = NNNCCCCC | + | or l |
- | ld l, a | + | ld l, a ; Establecemos el " |
; Finalmente, calcular posicion relativa del pixel: | ; Finalmente, calcular posicion relativa del pixel: | ||
- | ld a, c ; Recuperamos la coordenada X | + | ld a, c ; Recuperamos la coordenada X |
- | and 7 | + | and %00000111 |
- | | + | |
ret | ret | ||
</ | </ | ||
Línea 967: | Línea 943: | ||
|< 50% >| | |< 50% >| | ||
^ Valor de A ^ 7 ^ 6 ^ 5 ^ 4 ^ 3 ^ 2 ^ 1 ^ 0 ^ | ^ Valor de A ^ 7 ^ 6 ^ 5 ^ 4 ^ 3 ^ 2 ^ 1 ^ 0 ^ | ||
- | | Posición del pixel\\ desde la izquierda | +7 | +6 | +5 | +4 | +3 | +2 | +1 | +0 | | + | | Posición del pixel\\ desde la izquierda | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
| Posición del pixel\\ dentro del byte (Bit) | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | | | Posición del pixel\\ dentro del byte (Bit) | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | | ||
Línea 976: | Línea 952: | ||
Por otra parte, si necesitamos activar (PLOT, bit=1), desactivar (UNPLOT, b=0) o testear el estado del pixel (x,y), podremos utilizar este valor " | Por otra parte, si necesitamos activar (PLOT, bit=1), desactivar (UNPLOT, b=0) o testear el estado del pixel (x,y), podremos utilizar este valor " | ||
- | En ocasiones se puede reescribir una rutina de otra forma para ser ligeramente más eficiente: \\ //Dean Belfield//, en su página | + | Si queremos convertir la //posición del pixel// en una //máscara de pixel// (por ejemplo, convertir '' |
- | \\ | ||
<code z80> | <code z80> | ||
- | ; Get screen address | + | and %00000111 |
- | ; B = Y pixel position | + | ; A = 00000PPP, y además setear ZF si es 0 |
- | ; | + | ;--- Nuevo código --- |
- | ; Returns address in HL | + | |
- | ; | + | ld b, a |
- | Get_Pixel_Address: | + | ld a, %10000000 |
- | ld a, b ; Calculate Y2,Y1,Y0 | + | |
- | | + | ; entonces ya no necesitamos rotar |
- | | + | getpixoff_loop: |
- | ld h, a ; Store in H | + | rra |
- | ld a, b ; Calculate Y7,Y6 | + | |
- | rra ; Shift to position | + | getpixoff_norotate: |
- | rra | + | ; Ahora A es una máscara de pixel |
- | rra | + | ;--- Fin nuevo código --- |
- | and %00011000 | + | |
- | | + | |
- | ld h, a | + | |
- | ld a, b ; Calculate Y5,Y4,Y3 | + | |
- | rla ; Shift to position | + | |
- | rla | + | |
- | | + | |
- | ld l, a | + | |
- | ld a, c ; Calculate X4, | + | |
- | rra ; Shift into position | + | |
- | | + | |
- | rra | + | |
- | and %00011111 | + | |
- | | + | |
- | ld l, a ; Store in L | + | |
- | ret | + | |
- | </ | + | |
- | Finalmente, //David Black// en su web //Overtaken by events// nos ofrece la siguiente rutina de 105 t-estados y 26 bytes: | ||
- | |||
- | \\ | ||
- | <code z80> | ||
- | ; Get screen address | ||
- | ; B = Y pixel position | ||
- | ; C = X pixel position | ||
- | ; Returns address in HL | ||
- | Get_Screen_Address: | ||
- | ld a,b ; Work on the upper byte of the address | ||
- | and %00000111 | ||
- | or %01000000 | ||
- | ld h,a ; store in h | ||
- | ld a,b ; get bits Y7, Y6 | ||
- | rra ; move them into place | ||
- | rra ; | ||
- | rra ; | ||
- | and %00011000 | ||
- | or h ; a = 0 1 0 Y7 Y6 Y2 Y1 Y0 | ||
- | ld h,a ; calculation of h is now complete | ||
- | ld a,b ; get y | ||
- | rla ; | ||
- | rla ; | ||
- | and %11100000 | ||
- | ld l,a ; store in l | ||
- | ld a,c ; | ||
- | and %00011111 | ||
- | or l ; a = Y5 Y4 Y3 X4 X3 X2 X1 | ||
- | ld l,a ; calculation of l is complete | ||
ret | ret | ||
</ | </ | ||
Línea 1077: | Línea 1006: | ||
<code z80> | <code z80> | ||
- | ld b, a | + | ld b, a ; Cargamos A (posicion de pixel) en B |
- | inc b | + | inc b ; Incrementamos B (para pasadas del bucle) |
- | xor a | + | xor a ; A = 0 |
- | scf | + | scf ; Set Carry Flag (A=0, CF=1) |
pix_rotate_bit: | pix_rotate_bit: | ||
- | rra | + | rra ; Rotamos A a la derecha B veces |
djnz pix_rotate_bit | djnz pix_rotate_bit | ||
</ | </ | ||
Línea 1103: | Línea 1032: | ||
; | ; | ||
Relative_to_Mask: | Relative_to_Mask: | ||
- | ld b, a | + | ld b, a ; Cargamos A (posicion de pixel) en B |
- | inc b | + | inc b ; Incrementamos B (para pasadas del bucle) |
- | xor a | + | xor a ; A = 0 |
- | scf | + | scf ; Set Carry Flag (A=0, CF=1) |
pix_rotate_bit: | pix_rotate_bit: | ||
- | rra | + | rra ; Rotamos A a la derecha B veces |
djnz pix_rotate_bit | djnz pix_rotate_bit | ||
ret | ret | ||
Línea 1179: | Línea 1108: | ||
<code z80> | <code z80> | ||
- | ld c, 127 | + | ld c, 127 ; X = 127 |
- | ld b, 95 ; Y = 95 | + | ld b, 95 |
- | call Get_Pixel_Offset_HR | + | call Get_Pixel_Offset_HR |
- | or (hl) | + | or (hl) ; OR de A y (HL) |
- | ld (hl), a ; Activamos pixel | + | ld (hl), a |
</ | </ | ||
Línea 1271: | Línea 1200: | ||
; Imprimimos un solo pixel en (0,0) | ; Imprimimos un solo pixel en (0,0) | ||
- | ld c, 0 ; X = 0 | + | ld c, 0 ; X = 0 |
- | ld b, 0 ; Y = 0 | + | ld b, 0 ; Y = 0 |
- | ld a, b ; A = Y = 0 | + | ld a, b ; A = Y = 0 |
- | call PIXEL_ADDRESS | + | call PIXEL_ADDRESS |
- | ld a, 128 ; A = 10000000b (1 pixel). | + | ld a, 128 ; A = 10000000b (1 pixel). |
- | ld (hl), a | + | ld (hl), a |
; Imprimimos 8 pixeles en (255,191) | ; Imprimimos 8 pixeles en (255,191) | ||
- | ld c, 255 ; X = 255 | + | ld c, 255 ; X = 255 |
- | ld b, 191 ; Y = 191 | + | ld b, 191 ; Y = 191 |
- | ld a, b ; A = Y = 191 | + | ld a, b ; A = Y = 191 |
call PIXEL_ADDRESS | call PIXEL_ADDRESS | ||
- | ld a, 255 ; A = 11111111b (8 pixeles) | + | ld a, 255 ; A = 11111111b (8 pixeles) |
ld (hl), a | ld (hl), a | ||
; Imprimimos 4 pixeles en el centro de la pantalla | ; Imprimimos 4 pixeles en el centro de la pantalla | ||
- | ld c, 127 ; X = 127 | + | ld c, 127 ; X = 127 |
- | ld b, 95 | + | ld b, 95 |
- | ld a, b ; A = Y = 95 | + | ld a, b ; A = Y = 95 |
call PIXEL_ADDRESS | call PIXEL_ADDRESS | ||
- | ld a, 170 | + | ld a, %10101010 |
ld (hl), a | ld (hl), a | ||
- | loop: ; Bucle para no volver a BASIC y que | + | loop: ; Bucle para no volver a BASIC y que |
- | jr loop ; no se borren la 2 ultimas lineas | + | jr loop ; no se borren la 2 ultimas lineas |
END 50000 | END 50000 | ||
Línea 1317: | Línea 1246: | ||
; | ; | ||
PIXEL_ADDRESS_MASK: | PIXEL_ADDRESS_MASK: | ||
- | call PIXEL_ADDRESS | + | call PIXEL_ADDRESS |
- | ld b, a ; Cargamos A (posicion de pixel) en B | + | ld b, a ; Cargamos A (posicion de pixel) en B |
- | inc b ; Incrementamos B (para pasadas del bucle) | + | inc b ; Incrementamos B (para pasadas del bucle) |
- | xor a ; A = 0 | + | xor a ; A = 0 |
- | scf ; Set Carry Flag (A=0, CF=1) | + | scf ; Set Carry Flag (A=0, CF=1) |
pix_rotate_bit: | pix_rotate_bit: | ||
- | rra ; Rotamos A a la derecha B veces | + | rra ; Rotamos A a la derecha B veces |
djnz pix_rotate_bit | djnz pix_rotate_bit | ||
ret | ret | ||
Línea 1341: | Línea 1270: | ||
< | < | ||
DIRECCION_DESTINO | DIRECCION_DESTINO | ||
- | PIXEL_EN_DIRECCION = Resto(X/8) = X and 7 | + | PIXEL_EN_DIRECCION = Resto(X/8) = X AND %00000111 |
</ | </ | ||
Línea 1447: | Línea 1376: | ||
ld (hl), e | ld (hl), e | ||
inc l | inc l | ||
- | ld (hl), d | + | ld (hl), d |
- | inc hl | + | inc hl |
; Recorremos los scanlines y bloques en un bucle generando las | ; Recorremos los scanlines y bloques en un bucle generando las | ||
Línea 1455: | Línea 1384: | ||
inc d | inc d | ||
ld a, d | ld a, d | ||
- | and 7 | + | and %00000111 |
jr nz, genscan_nextline | jr nz, genscan_nextline | ||
ld a, e | ld a, e | ||
Línea 1486: | Línea 1415: | ||
; | ; | ||
Get_Pixel_Offset_LUT_HR: | Get_Pixel_Offset_LUT_HR: | ||
- | ld de, Scanline_Offsets | + | ld de, Scanline_Offsets |
- | ld l, b | + | ld l, b ; L = Y |
ld h, 0 | ld h, 0 | ||
- | add hl, hl ; HL = HL * 2 = Y * 2 | + | add hl, hl |
- | add hl, de ; HL = (Y*2) + ScanLine_Offset | + | add hl, de |
- | ; Ahora Offset = [HL] | + | |
- | ld a, (hl) ; Cogemos el valor bajo de la direccion en A | + | ld a, (hl) |
inc l | inc l | ||
- | ld h, (hl) ; Cogemos el valor alto de la direccion en H | + | ld h, (hl) |
- | ld l, a | + | ld l, a ; HL es ahora Direccion(0, |
- | ; Ahora sumamos la X, para lo cual calculamos CCCCC | + | |
- | ld a, c | + | ld a, c ; Calculamos columna |
rra | rra | ||
rra | rra | ||
- | rra | + | rra ; A = A>>3 = ???CCCCCb |
- | and 31 | + | and %00011111 |
- | add a, l ; HL = HL + C | + | add a, l |
ld l, a | ld l, a | ||
- | ld a, c | + | ld a, c ; Recuperamos la coordenada (X) |
- | and 7 ; A = Posicion relativa del pixel | + | and %00000111 |
- | ret | + | ret ; HL = direccion destino |
</ | </ | ||
Línea 1521: | Línea 1450: | ||
loop_draw: | loop_draw: | ||
- | push bc ; Preservamos B (por el bucle) | + | push bc ; Preservamos B (por el bucle) |
- | ld c, 127 ; X = 127, Y = B | + | ld c, 127 ; X = 127, Y = B |
call Get_Pixel_Offset_LUT_HR | call Get_Pixel_Offset_LUT_HR | ||
- | ld a, 128 | + | ld a, %10000000 |
- | ld (hl), a | + | ld (hl), a |
pop bc | pop bc | ||
djnz loop_draw | djnz loop_draw | ||
- | loop: ; Bucle para no volver a BASIC y que | + | loop: ; Bucle para no volver a BASIC y que |
- | jr loop ; no se borren la 2 ultimas lineas | + | jr loop ; no se borren la 2 ultimas lineas |
END 50000 | END 50000 | ||
Línea 1596: | Línea 1525: | ||
genscan_loop: | genscan_loop: | ||
- | ld (hl), e ; Escribimos parte baja | + | ld (hl), e |
- | inc h | + | inc h ; Saltamos a tabla de partes altas |
- | ld (hl), d ; Escribimos parte alta | + | ld (hl), d |
- | dec h | + | dec h ; Volvemos a tabla de partes bajas |
- | inc l | + | inc l ; Siguiente valor |
; Recorremos los scanlines y bloques en un bucle generando las | ; Recorremos los scanlines y bloques en un bucle generando las | ||
Línea 1607: | Línea 1536: | ||
inc d | inc d | ||
ld a, d | ld a, d | ||
- | and 7 | + | and %00000111 |
jr nz, genscan_nextline | jr nz, genscan_nextline | ||
ld a, e | ld a, e | ||
Línea 1702: | Línea 1631: | ||
; | ; | ||
Get_Pixel_Offset_LUT_2: | Get_Pixel_Offset_LUT_2: | ||
- | ld a, c | + | ld a, c |
rra | rra | ||
rra | rra | ||
- | rra | + | rra |
- | and 31 | + | and %00011111 |
- | ld l, b | + | ld l, b |
- | ld h, Scanline_Offsets/ | + | ld h, Scanline_Offsets/ |
- | add a, (hl) | + | add a, (hl) |
- | inc h | + | inc h |
- | ld h, (hl) ; cargamos en H la parte alta | + | ld h, (hl) ; cargamos en H la parte alta |
- | ld l, a | + | ld l, a |
- | ld a, c | + | ld a, c |
- | and 7 ; A = Posicion relativa del pixel | + | and %00000111 |
ret | ret | ||
</ | </ | ||
Línea 1763: | Línea 1692: | ||
Pixel_Izquierda_HL_Mask: | Pixel_Izquierda_HL_Mask: | ||
- | rlc a ; Rotamos A a la izquierda | + | rlc a ; Rotamos A a la izquierda |
- | ret nc | + | ret nc |
- | dec l ; Si se activa, hemos pasado de 10000000b | + | dec l ; Si se activa, hemos pasado de 10000000b |
- | ret ; a 00000001b y ya podemos alterar HL | + | ret ; a 00000001b y ya podemos alterar HL |
Pixel_Derecha_HL_Mask: | Pixel_Derecha_HL_Mask: | ||
- | rrc a ; Rotamos A a la derecha | + | rrc a ; Rotamos A a la derecha |
- | ret nc | + | ret nc |
- | inc l ; Si se activa, hemos pasado de 00000001b | + | inc l ; Si se activa, hemos pasado de 00000001b |
- | ret ; a 10000000b y ya podemos alterar HL | + | ret ; a 10000000b y ya podemos alterar HL |
</ | </ | ||
Línea 1786: | Línea 1715: | ||
Pixel_Derecha_HL_Rel: | Pixel_Derecha_HL_Rel: | ||
- | inc a ; Incrementamos A | + | inc a ; Incrementamos A |
- | and 7 ; Si A=8 -> A=0 | + | and %00000111 |
- | ret nz | + | ret nz |
- | inc l ; Si se activa, hemos pasado al byte | + | inc l ; Si se activa, hemos pasado al byte |
- | ret ; siguiente -> alterar HL | + | ret ; siguiente -> alterar HL |
Pixel_Izquierda_HL_Rel: | Pixel_Izquierda_HL_Rel: | ||
- | dec a ; Decrementamos A | + | dec a ; Decrementamos A |
- | ret p ; Si no hay overflow (A de 0 a 255), fin | + | ret p ; Si no hay overflow (A de 0 a 255), fin |
- | and 7 ; 11111111b -> 00000111b | + | and %00000111 |
- | dec l ; Hemos pasado al byte siguiente -> | + | dec l ; Hemos pasado al byte siguiente -> |
- | ret ; alteramos HL | + | ret ; alteramos HL |
</ | </ | ||
Línea 1818: | Línea 1747: | ||
<code z80> | <code z80> | ||
; Avanzamos HL 1 scanline: | ; Avanzamos HL 1 scanline: | ||
- | inc h | + | inc h ; Incrementamos HL en 256 (siguiente scanline) |
- | ld a, h | + | ld a, h ; Cargamos H en A |
- | and 7 ; Si despues del inc h los 3 bits son 0, | + | and %00000111 |
- | ; es porque era 111b y ahora 1000b. | + | |
- | jr nz, nofix_abajop | + | jr nz, nofix_abajop |
- | ld a, l | + | ld a, l ; Es cero, hemos pasado del scanline 7 de un |
- | ; caracter al 0 del siguiente: ajustar NNN | + | |
- | add a, 32 ; Ajustamos NNN (caracter dentro de tercio += 1) | + | add a, %00100000 |
- | ld l, a | + | ld l, a ; Ahora hacemos la comprobacion de salto de tercio |
- | jr c, nofix_abajop | + | jr c, nofix_abajop |
- | ; tercio, pero ya lo hizo el inc h (111b -> 1000b) | + | |
- | ld a, h | + | ld a, h ; Si no produce acarreo, no hay que ajustar |
- | sub 8 ; tercio, por lo que restamos el bit TT que sumo | + | sub %00001000 |
- | ld h, a | + | ld h, a ; el inc h inicial. |
nofix_abajop: | nofix_abajop: | ||
Línea 1842: | Línea 1771: | ||
<code z80> | <code z80> | ||
ld a, h | ld a, h | ||
- | and 7 ; Comprobamos scanline | + | and %00000111 |
- | jr z, Anterior_SL_DEC | + | jr z, Anterior_SL_DEC |
- | dec h | + | dec h ; No es cero, basta HL = HL - 256 |
- | ret | + | ret ; Hemos acabado (solo inc h). |
- | Anterior_SL_DEC: | + | Anterior_SL_DEC: |
- | dec h | + | dec h ; Decrementamos H |
- | ld a, l | + | ld a, l ; Ajustamos NNN (caracter en tercio -=1) |
- | sub 32 | + | sub %00100000 |
ld l, a | ld l, a | ||
- | ret c | + | ret c ; Si se produjo carry, no hay que ajustar |
- | ld a, h | + | ld a, h ; Se produjo carry, ajustamos el tercio |
- | add a, 8 | + | add a, %00001000 |
ld h, a | ld h, a | ||
</ | </ | ||
Línea 1874: | Línea 1803: | ||
inc h | inc h | ||
ld a, h | ld a, h | ||
- | and 7 | + | and %00000111 |
ret nz | ret nz | ||
ld a, l | ld a, l | ||
- | add a, 32 | + | add a, %00100000 |
ld l, a | ld l, a | ||
ret c | ret c | ||
ld a, h | ld a, h | ||
- | sub 8 | + | sub %00001000 |
ld h, a | ld h, a | ||
- | ret | + | ret ; Devolvemos en HL el valor ajustado |
</ | </ | ||
Línea 1903: | Línea 1832: | ||
ld a, h | ld a, h | ||
dec h | dec h | ||
- | and 7 | + | and %00000111 |
ret nz | ret nz | ||
- | ld a, 8 | + | ld a, %00001000 |
add a, h | add a, h | ||
ld h, a | ld h, a | ||
ld a, l | ld a, l | ||
- | sub 32 | + | sub %00100000 |
ld l, a | ld l, a | ||
ret nc | ret nc | ||
ld a, h | ld a, h | ||
- | sub 8 | + | sub %00001000 |
ld h, a | ld h, a | ||
- | ret | + | ret ; Devolvemos en HL el valor ajustado |
</ | </ | ||
Línea 1943: | Línea 1872: | ||
rrca | rrca | ||
rrca | rrca | ||
- | and 3 | + | and %00000011 |
- | or $58 | + | or %01011000 |
ld d, a | ld d, a | ||
ld e, l | ld e, l | ||
Línea 1961: | Línea 1890: | ||
Image_Offset_From_Attr: | Image_Offset_From_Attr: | ||
ld a, h | ld a, h | ||
- | and 3 | + | and %00000011 |
rlca | rlca | ||
rlca | rlca | ||
rlca | rlca | ||
- | or $40 | + | or %01000000 |
ld d, a | ld d, a | ||
ld e, l | ld e, l | ||
Línea 1984: | Línea 1913: | ||
Get_Char_Data: | Get_Char_Data: | ||
ld a, b | ld a, b | ||
- | and $18 | + | and %00011000 |
ld h, a | ld h, a | ||
set 6, h | set 6, h | ||
Línea 1990: | Línea 1919: | ||
rrca | rrca | ||
rrca | rrca | ||
- | or $58 | + | or %01011000 |
ld d, a | ld d, a | ||
ld a, b | ld a, b | ||
- | and 7 | + | and %00000111 |
rrca | rrca | ||
rrca | rrca | ||
Línea 2005: | Línea 1934: | ||
| | ||
+ | |||
+ | \\ | ||
+ | ===== Optimizaciones para Get_Pixel_Offset_HR ===== | ||
+ | |||
+ | En ocasiones se puede reescribir una rutina de otra forma para ser ligeramente más eficiente, y las rutinas relacionadas con los gráficos (tanto " | ||
+ | |||
+ | \\ //Dean Belfield//, en su página //L Break Into Program// nos proporciona la siguiente rutina optimizada para obtener la dirección de memoria de un pixel dadas su coordenadas (x,y) que requiere 117 t-estados, a costa de no devolvernos la posición relativa del pixel: | ||
+ | |||
+ | \\ | ||
+ | <code z80> | ||
+ | ; Get screen address - by Dean Belfield | ||
+ | ; | ||
+ | ; B = Y pixel position | ||
+ | ; C = X pixel position | ||
+ | ; Returns address in HL | ||
+ | Get_Pixel_Address: | ||
+ | ld a, b ; Calculate Y2,Y1,Y0 | ||
+ | and %00000111 | ||
+ | or %01000000 | ||
+ | ld h, a ; Store in H | ||
+ | ld a, b ; Calculate Y7,Y6 | ||
+ | rra ; Shift to position | ||
+ | rra | ||
+ | rra | ||
+ | and %00011000 | ||
+ | or h ; OR with Y2,Y1,Y0 | ||
+ | ld h, a ; Store in H | ||
+ | ld a, b ; Calculate Y5,Y4,Y3 | ||
+ | rla ; Shift to position | ||
+ | rla | ||
+ | and %11100000 | ||
+ | ld l, a ; Store in L | ||
+ | ld a, c ; Calculate X4, | ||
+ | rra ; Shift into position | ||
+ | rra | ||
+ | rra | ||
+ | and %00011111 | ||
+ | or l ; OR with Y5,Y4,Y3 | ||
+ | ld l, a ; Store in L | ||
+ | ret | ||
+ | </ | ||
+ | |||
+ | Finalmente, //David Black// en su web //Overtaken by events// nos ofrece la siguiente rutina de 105 t-estados y 26 bytes: | ||
+ | |||
+ | \\ | ||
+ | <code z80> | ||
+ | ; Get screen address - by David Black | ||
+ | ; B = Y pixel position | ||
+ | ; C = X pixel position | ||
+ | ; Returns address in HL | ||
+ | Get_Screen_Address: | ||
+ | ld a,b ; Work on the upper byte of the address | ||
+ | and %00000111 | ||
+ | or %01000000 | ||
+ | ld h,a ; store in h | ||
+ | ld a,b ; get bits Y7, Y6 | ||
+ | rra ; move them into place | ||
+ | rra | ||
+ | rra | ||
+ | and %00011000 | ||
+ | or h ; a = 0 1 0 Y7 Y6 Y2 Y1 Y0 | ||
+ | ld h,a ; calculation of h is now complete | ||
+ | ld a,b ; get y | ||
+ | rla | ||
+ | rla | ||
+ | and %11100000 | ||
+ | ld l,a ; store in l | ||
+ | ld a,c | ||
+ | and %00011111 | ||
+ | or l ; a = Y5 Y4 Y3 X4 X3 X2 X1 | ||
+ | ld l,a ; calculation of l is complete | ||
+ | ret | ||
+ | </ | ||
+ | |||
+ | Utilizando tablas, en esta misma web podemos ver las siguientes 2 aproximaciones de //Patrick Prendergast// | ||
+ | |||
+ | <code z80> | ||
+ | ; Store the LUT table in the format "y5 y4 y3 y7 y6 y2 y1 y0" | ||
+ | ; Lower 5 bits where you need them for y and upper 3 bits to mask | ||
+ | ; out to OR with X (which are replaced with 010 anyway). | ||
+ | ; This way you'd only need 192 bytes for the table, which could be | ||
+ | ; page-aligned for speed. You'd be looking at 69 cycles por request | ||
+ | ; and 16 + 192 for the code + table. | ||
+ | ; | ||
+ | ; By Patrick Prendergast. | ||
+ | |||
+ | ; b = y, c = x | ||
+ | getScreenAddress: | ||
+ | ld h,tbl >> 8 | ||
+ | ld l,b | ||
+ | ld h,(hl) | ||
+ | ld a,%11100000 | ||
+ | and h | ||
+ | or c | ||
+ | ld l,a | ||
+ | ld a,%00011111 | ||
+ | and h | ||
+ | or %01000000 | ||
+ | ld h,a | ||
+ | ret | ||
+ | |||
+ | tbl: ; y5 y4 y3 y7 y6 y2 y1 y0 | ||
+ | .db 0, | ||
+ | | ||
+ | |||
+ | ; Option 2: if you are willing to [potentially] sacrifice | ||
+ | ; some space for speed, you can divide the table so that | ||
+ | ; you have the low and high bytes of your address list in | ||
+ | ; 2 independent tables and have them both page aligned - | ||
+ | ; with the low byte first in memory. | ||
+ | ; This would completely remove to need to calc y*2 to get | ||
+ | ; to your table offset. | ||
+ | ; This would require 64 bytes of padding after the 1st table | ||
+ | ; (due to both tables being page aligned) meaning you would | ||
+ | ; need 448 bytes all up. That being said the 64 bytes of | ||
+ | ; padding space is not needed so you can include any other | ||
+ | ; data you might need there so it's not wasted. | ||
+ | ; Then you would only need 47 cycles to lookup your address! | ||
+ | ; | ||
+ | ; By Patrick Prendergast. | ||
+ | |||
+ | ; b = y, c = x | ||
+ | getScreenAddress: | ||
+ | ld h,tblLow >> 8 | ||
+ | ld l,b | ||
+ | ld a,(hl) | ||
+ | inc h | ||
+ | ld h,(hl) | ||
+ | or c | ||
+ | ld l,a | ||
+ | ret | ||
+ | |||
+ | ALIGN 256 | ||
+ | tblLow: ; (ADDR & 0xFF) | ||
+ | .db 0, | ||
+ | |||
+ | ALIGN 256 | ||
+ | tblHigh: ; (ADDR >> 8) | ||
+ | .db 64, | ||
+ | </ | ||
+ | |||
+ | Estas rutinas son realmente rápidas, teniendo la segunda un coste de sólo 47 t-estados por cálculo de dirección, a costa de ocupar más espacio por separar la parte alta y la parte baja de la tabla precalculada, | ||
\\ | \\ | ||
Línea 2023: | Línea 2094: | ||
* [[http:// | * [[http:// | ||
* [[http:// | * [[http:// | ||
+ | * [[https:// | ||
\\ | \\ | ||
**[ [[.: | **[ [[.: | ||