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 [08-01-2024 05:54] – sromero | cursos:ensamblador:gfx2_direccionamiento [21-01-2024 17:22] (actual) – [Optimizaciones para Get_Pixel_Offset_HR] sromero | ||
---|---|---|---|
Línea 54: | Línea 54: | ||
\\ | \\ | ||
* **Área de imagen**: | * **Área de imagen**: | ||
- | * El área de imagen se divide en 3 tercios de pantalla de 2KB de memoria cada uno, que van de $4000 a $47FF (tercio superior), de $4800 a $4FFF (tercio central) y de $5000 a $57FF (tercio inferior). | + | * El área de imagen se divide en 3 tercios de pantalla de 2KB de memoria cada uno, que van de $4000 a $47ff (tercio superior), de $4800 a $4fff (tercio central) y de $5000 a $57ff (tercio inferior). |
* Cada uno de los tercios comprende 8 líneas de 32 bloques horizontales (256x64 píxeles). Dentro de cada uno de esos 2KB, tenemos, de forma lineal, 64 bloques de 32 bytes (256 píxeles) de información que representan cada scanline de esos 8 bloques. | * Cada uno de los tercios comprende 8 líneas de 32 bloques horizontales (256x64 píxeles). Dentro de cada uno de esos 2KB, tenemos, de forma lineal, 64 bloques de 32 bytes (256 píxeles) de información que representan cada scanline de esos 8 bloques. | ||
* Los primeros 32 bytes de dicho bloque contienen la información del scanline 0 del bloque 0. Avanzando de 32 en 32 bytes tenemos los datos del scanline 0 del bloque 1, el scanline 0 del bloque 2, el scanline 0 del bloque 3, etc, hasta que llegamos al scanline 7 del bloque 0. Los siguientes 32 bytes repiten el proceso pero con el scanline 1 de cada bloque. | * Los primeros 32 bytes de dicho bloque contienen la información del scanline 0 del bloque 0. Avanzando de 32 en 32 bytes tenemos los datos del scanline 0 del bloque 1, el scanline 0 del bloque 2, el scanline 0 del bloque 3, etc, hasta que llegamos al scanline 7 del bloque 0. Los siguientes 32 bytes repiten el proceso pero con el scanline 1 de cada bloque. | ||
Línea 66: | Línea 66: | ||
* **Area de atributos**: | * **Area de atributos**: | ||
* El área de atributos se encuentra en memoria inmediatamente después del área de imagen, por lo que empieza en la posición de memoria 16384+6144 = 22528 ($5800). | * El área de atributos se encuentra en memoria inmediatamente después del área de imagen, por lo que empieza en la posición de memoria 16384+6144 = 22528 ($5800). | ||
- | * Cada byte del área de atributos se denomina // | + | * Cada byte del área de atributos se denomina // |
* Los diferentes bits de un atributo de carácter son: Bit 7 = FLASH, Bit 6 = BRIGHT, Bits 5-3 = PAPER, Bits 2-0 = INK. | * Los diferentes bits de un atributo de carácter son: Bit 7 = FLASH, Bit 6 = BRIGHT, Bits 5-3 = PAPER, Bits 2-0 = INK. | ||
* Los valores de tinta y papel son un valor de 0-7 que junto al brillo como bit más significativo componen un índice (B-I-I-I) contra una paleta de colores interna definida en la ULA, donde el 0 es el color negro y el 15 el blanco de brillo máximo. | * Los valores de tinta y papel son un valor de 0-7 que junto al brillo como bit más significativo componen un índice (B-I-I-I) contra una paleta de colores interna definida en la ULA, donde el 0 es el color negro y el 15 el blanco de brillo máximo. | ||
Línea 98: | Línea 98: | ||
\\ | \\ | ||
- | Es importante comprobar antes de llamar a nuestras rutinas si estas modifican algún registro o flag que necesitemos preservar. Podemos modificar las rutinas para que realicen PUSH y POP de los registros necesarios o hacer nosotros estos PUSH/POP en la rutina llamadora. | + | Es importante comprobar antes de llamar a nuestras rutinas si estas modifican algún registro o flag que necesitemos preservar. Podemos modificar las rutinas para que realicen |
| | ||
Línea 116: | Línea 116: | ||
| 3 | $5860 | 22624 | 0101100001100000b | | | 3 | $5860 | 22624 | 0101100001100000b | | ||
| 4 | $5880 | 22656 | 0101100010000000b | | | 4 | $5880 | 22656 | 0101100010000000b | | ||
- | | 5 | $58A0 | 22688 | 0101100010100000b | | + | | 5 | $58a0 | 22688 | 0101100010100000b | |
- | | 6 | $58C0 | 22720 | 0101100011000000b | | + | | 6 | $58c0 | 22720 | 0101100011000000b | |
- | | 7 | $58E0 | 22752 | 0101100011100000b | | + | | 7 | $58e0 | 22752 | 0101100011100000b | |
| 8 | $5900 | 22784 | 0101100100000000b | | | 8 | $5900 | 22784 | 0101100100000000b | | ||
| 9 | $5920 | 22816 | 0101100100100000b | | | 9 | $5920 | 22816 | 0101100100100000b | | ||
Línea 124: | Línea 124: | ||
| 11 | $5960 | 22880 | 0101100101100000b | | | 11 | $5960 | 22880 | 0101100101100000b | | ||
| 12 | $5980 | 22912 | 0101100110000000b | | | 12 | $5980 | 22912 | 0101100110000000b | | ||
- | | 13 | $59A0 | 22944 | 0101100110100000b | | + | | 13 | $59a0 | 22944 | 0101100110100000b | |
- | | 14 | $59C0 | 22976 | 0101100111000000b | | + | | 14 | $59c0 | 22976 | 0101100111000000b | |
- | | 15 | $59E0 | 23008 | 0101100111100000b | | + | | 15 | $59e0 | 23008 | 0101100111100000b | |
- | | 16 | $5A00 | 23040 | 0101101000000000b | | + | | 16 | $5a00 | 23040 | 0101101000000000b | |
- | | 17 | $5A20 | 23072 | 0101101000100000b | | + | | 17 | $5a20 | 23072 | 0101101000100000b | |
- | | 18 | $5A40 | 23104 | 0101101001000000b | | + | | 18 | $5a40 | 23104 | 0101101001000000b | |
- | | 19 | $5A60 | 23136 | 0101101001100000b | | + | | 19 | $5a60 | 23136 | 0101101001100000b | |
- | | 20 | $5A80 | 23168 | 0101101010000000b | | + | | 20 | $5a80 | 23168 | 0101101010000000b | |
- | | 21 | $5AA0 | 23200 | 0101101010100000b | | + | | 21 | $5aa0 | 23200 | 0101101010100000b | |
- | | 22 | $5AC0 | 23232 | 0101101011000000b | | + | | 22 | $5ac0 | 23232 | 0101101011000000b | |
- | | 23 | $5AE0 | 23264 | 0101101011100000b | | + | | 23 | $5ae0 | 23264 | 0101101011100000b | |
// | // | ||
\\ | \\ | ||
Línea 167: | Línea 167: | ||
Get_Attribute_Offset_LR_SLOW: | Get_Attribute_Offset_LR_SLOW: | ||
; calcular dir_atributo como " | ; calcular dir_atributo como " | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
Línea 197: | Línea 197: | ||
| 4 | $5880 | 22656 | // | | 4 | $5880 | 22656 | // | ||
| (...) | (...) | (...) | (...) | | | (...) | (...) | (...) | (...) | | ||
- | | 21 | $5AA0 | 23200 | // | + | | 21 | $5aa0 | 23200 | // |
- | | 22 | $5AC0 | 23232 | // | + | | 22 | $5ac0 | 23232 | // |
- | | 23 | $5AE0 | 23264 | // | + | | 23 | $5ae0 | 23264 | // |
- | * Los 6 bits más significativos de la dirección son 010110, que es la parte de la dirección que provoca que todas las posiciones estén entre $5800 y $5AFF. | + | * Los 6 bits más significativos de la dirección son 010110, que es la parte de la dirección que provoca que todas las posiciones estén entre $5800 y $5aff. |
* Los bits 5, 6, 7 y 8 se corresponden con la fila que queremos consultar. | * Los bits 5, 6, 7 y 8 se corresponden con la fila que queremos consultar. | ||
* Los bits 0, 1, 2, 3 y 4 los utilizaremos para acceder a a la columna deseada. En la tabla anterior son siempre 0 porque estamos mostrando las direcciones de inicio de cada fila, es decir, de (0,f), por lo que estos bits 0-4 son 0. | * Los bits 0, 1, 2, 3 y 4 los utilizaremos para acceder a a la columna deseada. En la tabla anterior son siempre 0 porque estamos mostrando las direcciones de inicio de cada fila, es decir, de (0,f), por lo que estos bits 0-4 son 0. | ||
Línea 226: | Línea 226: | ||
; | ; | ||
Get_Attribute_Offset_LR: | Get_Attribute_Offset_LR: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
- | La rutina realiza operaciones de bits para ubicar los datos de FILA, COLUMNA y 010011b en las posiciones que requiere la dirección destino final. Aconsejamos al lector revisar el capítulo dedicado a // | + | La rutina realiza operaciones de bits para ubicar los datos de FILA, COLUMNA y 010011b en las posiciones que requiere la dirección destino final. Aconsejamos al lector revisar el capítulo dedicado a // |
- | El coste de ejecución de esta rutina es de (RET aparte) 70 t-estados y no hace uso de DE, lo que es un ahorro sustancial tanto en tiempo de ejecución como en preservación de un registro muy utilizado. | + | El coste de ejecución de esta rutina es de ('' |
La salida de esta rutina se puede utilizar directamente para almacenar en (HL) el atributo del caracter (c,f) cuya direccion hemos solicitado: | La salida de esta rutina se puede utilizar directamente para almacenar en (HL) el atributo del caracter (c,f) cuya direccion hemos solicitado: | ||
<code z80> | <code z80> | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
La rutina no hace ningún tipo de comprobación del rango de COLUMNA y FILA, por lo que si proporcionamos valores menores de cero o mayores de 31 o 23 respectivamente se devolverá una dirección de memoria fuera del área de atributos. | La rutina no hace ningún tipo de comprobación del rango de COLUMNA y FILA, por lo que si proporcionamos valores menores de cero o mayores de 31 o 23 respectivamente se devolverá una dirección de memoria fuera del área de atributos. | ||
- | La versión para coordenadas en alta resolución de la anterior rutina (**Get_Attribute_Offset_HR(x, | + | La versión para coordenadas en alta resolución de la anterior rutina ('' |
Para eso, las primeras líneas de la rutina deberían ser: | Para eso, las primeras líneas de la rutina deberían ser: | ||
<code z80> | <code z80> | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
- | Una vez obtenido (c,f), el desarrollo de la rutina es el mismo que en el caso de Get_Attribute_Offset_LR(c, | + | Una vez obtenido (c,f), el desarrollo de la rutina es el mismo que en el caso de '' |
<code z80> | <code z80> | ||
Línea 287: | Línea 287: | ||
; | ; | ||
Get_Attribute_Offset_HR: | Get_Attribute_Offset_HR: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | + | | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
Línea 332: | Línea 331: | ||
; | ; | ||
Get_Attribute_Coordinates_LR: | Get_Attribute_Coordinates_LR: | ||
- | | + | ; Descomponemos HL = 010110FF FFFCCCCCb |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
De nuevo, el código no incluye ningún tipo de control sobre la dirección que se le proporciona, | De nuevo, el código no incluye ningún tipo de control sobre la dirección que se le proporciona, | ||
- | La rutina para trabajar con coordenadas en alta resolución (**Get_Attribute_Coordinates_HR(x, | + | La rutina para trabajar con coordenadas en alta resolución ('' |
<code z80> | <code z80> | ||
Línea 369: | Línea 368: | ||
; | ; | ||
Get_Attribute_Coordinates_HR: | Get_Attribute_Coordinates_HR: | ||
- | ; Descomponemos HL = 010110FF FFFCCCCCb | + | ; Descomponemos HL = 010110FF FFFCCCCCb |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
Línea 409: | Línea 408: | ||
<code z80> | <code z80> | ||
Atributo_derecha: | Atributo_derecha: | ||
- | | + | |
Atributo_izquierda: | Atributo_izquierda: | ||
- | | + | |
Atributo_abajo: | Atributo_abajo: | ||
- | | + | |
- | | + | |
Atributo_arriba: | Atributo_arriba: | ||
- | | + | |
- | | + | |
</ | </ | ||
Línea 427: | Línea 426: | ||
<code z80> | <code z80> | ||
Atributo_abajo_sin_usar_DE_2: | Atributo_abajo_sin_usar_DE_2: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | attrab_noinc: | + | attrab_noinc: |
Atributo_arriba_sin_usar_DE: | Atributo_arriba_sin_usar_DE: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | attrab_nodec: | + | attrab_nodec: |
</ | </ | ||
Línea 447: | Línea 446: | ||
<code z80> | <code z80> | ||
- | | + | |
- | | + | |
attrab_noinc: | attrab_noinc: | ||
</ | </ | ||
Línea 455: | Línea 454: | ||
<code z80> | <code z80> | ||
- | | + | |
- | ; o un "OR A" porque afectariamos al Carry Flag. | + | |
- | | + | |
- | | + | |
- | ; Ahora HL = (H+CF)*256 + (L+32) = HL + 32 | + | |
</ | </ | ||
- | Este código no utiliza DE pero se apoya en el registro A para los cálculos. Si necesitamos preservar su valor, siempre podemos realizar un **EX AF, AF** antes y después de la ejecución de la rutina. | + | Este código no utiliza DE pero se apoya en el registro A para los cálculos. Si necesitamos preservar su valor, siempre podemos realizar un '' |
\\ | \\ | ||
Línea 483: | Línea 482: | ||
\\ | \\ | ||
- | | + | |
Línea 503: | Línea 502: | ||
| 3 | $4060 | 16480 | 0100000001100000b | 0 (00b) | 3 | | | 3 | $4060 | 16480 | 0100000001100000b | 0 (00b) | 3 | | ||
| 4 | $4080 | 16512 | 0100000010000000b | 0 (00b) | 4 | | | 4 | $4080 | 16512 | 0100000010000000b | 0 (00b) | 4 | | ||
- | | 5 | $40A0 | 16544 | 0100000010100000b | 0 (00b) | 5 | | + | | 5 | $40a0 | 16544 | 0100000010100000b | 0 (00b) | 5 | |
- | | 6 | $40C0 | 16576 | 0100000011000000b | 0 (00b) | 6 | | + | | 6 | $40c0 | 16576 | 0100000011000000b | 0 (00b) | 6 | |
- | | 7 | $40E0 | 16608 | 0100000011100000b | 0 (00b) | 7 | | + | | 7 | $40e0 | 16608 | 0100000011100000b | 0 (00b) | 7 | |
| 8 | $4800 | 18432 | 0100100000000000b | 1 (01b) | 0 | | | 8 | $4800 | 18432 | 0100100000000000b | 1 (01b) | 0 | | ||
| 9 | $4820 | 18464 | 0100100000100000b | 1 (01b) | 1 | | | 9 | $4820 | 18464 | 0100100000100000b | 1 (01b) | 1 | | ||
Línea 511: | Línea 510: | ||
| 11 | $4860 | 18528 | 0100100001100000b | 1 (01b) | 3 | | | 11 | $4860 | 18528 | 0100100001100000b | 1 (01b) | 3 | | ||
| 12 | $4880 | 18560 | 0100100010000000b | 1 (01b) | 4 | | | 12 | $4880 | 18560 | 0100100010000000b | 1 (01b) | 4 | | ||
- | | 13 | $48A0 | 18592 | 0100100010100000b | 1 (01b) | 5 | | + | | 13 | $48a0 | 18592 | 0100100010100000b | 1 (01b) | 5 | |
- | | 14 | $48C0 | 18624 | 0100100011000000b | 1 (01b) | 6 | | + | | 14 | $48c0 | 18624 | 0100100011000000b | 1 (01b) | 6 | |
- | | 15 | $48E0 | 18656 | 0100100011100000b | 1 (01b) | 7 | | + | | 15 | $48e0 | 18656 | 0100100011100000b | 1 (01b) | 7 | |
| 16 | $5000 | 20480 | 0101000000000000b | 2 (10b) | 0 | | | 16 | $5000 | 20480 | 0101000000000000b | 2 (10b) | 0 | | ||
| 17 | $5020 | 20512 | 0101000000100000b | 2 (10b) | 1 | | | 17 | $5020 | 20512 | 0101000000100000b | 2 (10b) | 1 | | ||
Línea 519: | Línea 518: | ||
| 19 | $5060 | 20576 | 0101000001100000b | 2 (10b) | 3 | | | 19 | $5060 | 20576 | 0101000001100000b | 2 (10b) | 3 | | ||
| 20 | $5080 | 20608 | 0101000010000000b | 2 (10b) | 4 | | | 20 | $5080 | 20608 | 0101000010000000b | 2 (10b) | 4 | | ||
- | | 21 | $50A0 | 20640 | 0101000010100000b | 2 (10b) | 5 | | + | | 21 | $50a0 | 20640 | 0101000010100000b | 2 (10b) | 5 | |
- | | 22 | $50C0 | 20672 | 0101000011000000b | 2 (10b) | 6 | | + | | 22 | $50c0 | 20672 | 0101000011000000b | 2 (10b) | 6 | |
- | | 23 | $50E0 | 20704 | 0101000011100000b | 2 (10b) | 7 | | + | | 23 | $50e0 | 20704 | 0101000011100000b | 2 (10b) | 7 | |
\\ | \\ | ||
Línea 537: | Línea 536: | ||
| 10 | $4840 | 18496 | **010**// | | 10 | $4840 | 18496 | **010**// | ||
| (...) | (...) | (...) | (...) | (...) | (...) | | | (...) | (...) | (...) | (...) | (...) | (...) | | ||
- | | 23 | $50E0 | 20704 | **010**// | + | | 23 | $50e0 | 20704 | **010**// |
Lo primero que puede llamarnos la atención es lo siguiente: | Lo primero que puede llamarnos la atención es lo siguiente: | ||
Línea 548: | Línea 547: | ||
* Conclusión: | * Conclusión: | ||
* Hay una relación directa entre el número de fila dentro de cada tercio (0-7) y los 3 bits superiores (5-7) del byte bajo de la dirección. | * Hay una relación directa entre el número de fila dentro de cada tercio (0-7) y los 3 bits superiores (5-7) del byte bajo de la dirección. | ||
- | * Los 3 bytes más significativos de la dirección son siempre 010b. Esta es la parte de la composición de la dirección que ubica el offset en memoria en el rango de direcciones del área de imagen de la videoram ($4000 a $57FF). | + | * Los 3 bytes más significativos de la dirección son siempre 010b. Esta es la parte de la composición de la dirección que ubica el offset en memoria en el rango de direcciones del área de imagen de la videoram ($4000 a $57ff). |
* Los 5 bytes menos significativos de la dirección son siempre cero en la tabla. En realidad, representan a la columna (posición c de carácter dentro de los 32 bytes de datos horizontales) pero al estar calculando direcciones de inicio de línea (c = 0 = 00000b), en nuestro caso son siempre cero. | * Los 5 bytes menos significativos de la dirección son siempre cero en la tabla. En realidad, representan a la columna (posición c de carácter dentro de los 32 bytes de datos horizontales) pero al estar calculando direcciones de inicio de línea (c = 0 = 00000b), en nuestro caso son siempre cero. | ||
\\ | \\ | ||
Línea 577: | Línea 576: | ||
; | ; | ||
Get_Line_Offset_LR: | Get_Line_Offset_LR: | ||
- | | + | |
- | | + | |
- | ; A = estado de bits de TERCIO desde FILA | + | |
- | | + | |
- | | + | |
- | ; H = 010TT000 | + | |
- | | + | |
- | | + | |
- | ; que coinciden con FT (Fila dentro del tercio) | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
Línea 629: | Línea 628: | ||
; | ; | ||
Get_Char_Offset_LR: | Get_Char_Offset_LR: | ||
- | | + | |
- | | + | |
- | ; A = estado de bits de TERCIO desde FILA | + | |
- | | + | |
- | | + | |
- | ; H = 010TT000 | + | |
- | | + | |
- | | + | |
- | ; que coinciden con FT (Fila dentro del tercio) | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
Línea 658: | Línea 657: | ||
; | ; | ||
Get_Char_Offset_HR: | Get_Char_Offset_HR: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | (...) | + | (...) ; Resto de la rutina Get_Char_Offset_LR |
- | | + | |
</ | </ | ||
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 | ||
- | LD A, L ; A = L, para extraer los bits de N (FT) | + | ; Calculo de la fila: |
- | | + | ld a, h |
- | RLC A ; Rotamos A 3 veces a la izquierda | + | |
- | RLC A | + | |
- | RLC A ; A = 00000NNNb | + | |
- | OR B ; A = A OR B = 000TTNNNb | + | |
- | | + | |
- | ; Calculo de la columna: | + | ld a, l ; A = L, para extraer los bits de N (FT) |
- | | + | and %0b11100000 |
- | | + | rlc a ; Rotamos A 3 veces a la izquierda |
- | | + | rlc a |
- | | + | rlc a ; A = 00000NNNb |
+ | or b | ||
+ | ld b, a ; B = A = 000TTNNNb | ||
+ | |||
+ | ; Calculo de la columna: | ||
+ | | ||
+ | | ||
+ | | ||
+ | ret ; HL = 010TT000NNNCCCCCb | ||
</ | </ | ||
- | | + | |
<code z80> | <code z80> | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
Línea 729: | Línea 729: | ||
**Recorrer los 8 scanlines de un bloque** | **Recorrer los 8 scanlines de un bloque** | ||
- | Dada en HL la dirección del primer scanline de un bloque, podemos avanzar a lo largo de los 7 scanlines del mismo bloque sumando " | + | Dada en HL la dirección del primer scanline de un bloque, podemos avanzar a lo largo de los 7 scanlines del mismo bloque sumando " |
<code z80> | <code z80> | ||
Scanline_Arriba_HL: | Scanline_Arriba_HL: | ||
- | | + | |
Scanline_Abajo_HL: | Scanline_Abajo_HL: | ||
- | | + | |
</ | </ | ||
Línea 752: | Línea 752: | ||
<code z80> | <code z80> | ||
Caracter_Derecha_HL: | Caracter_Derecha_HL: | ||
- | | + | |
Caracter_Izquierda_HL: | Caracter_Izquierda_HL: | ||
- | | + | |
</ | </ | ||
Línea 774: | Línea 774: | ||
<code z80> | <code z80> | ||
- | LD A, L ; Cargamos A en L y le sumamos 32 para | + | Caracter_Abajo_HL: |
- | | + | ld a, l ; Cargamos A en L y le sumamos 32 para |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
+ | | ||
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: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
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 930: | Línea 906: | ||
; Calculo de la parte alta de la direccion: | ; Calculo de la parte alta de la direccion: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
; Calculo de la parte baja de la direccion: | ; Calculo de la parte baja de la direccion: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
; Finalmente, calcular posicion relativa del pixel: | ; Finalmente, calcular posicion relativa del pixel: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
- | Esta rutina de 118 t-estados nos devuelve el valor de la dirección calculado en HL y la posición relativa del pixel dentro del byte: | + | Esta rutina de 128 t-estados nos devuelve el valor de la dirección calculado en HL y la posición relativa del pixel dentro del byte: |
|< 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 " | ||
+ | Si queremos convertir la //posición del pixel// en una //máscara de pixel// (por ejemplo, convertir '' | ||
+ | |||
+ | <code z80> | ||
+ | and %00000111 | ||
+ | ; A = 00000PPP, y además setear ZF si es 0 | ||
+ | ;--- Nuevo código --- | ||
+ | | ||
+ | ld b, a ; Poner en B el numero de pixel | ||
+ | ld a, %10000000 | ||
+ | jr z, getpixoff_norotate | ||
+ | ; entonces ya no necesitamos rotar | ||
+ | getpixoff_loop: | ||
+ | rra ; Rotar A a la derecha B veces | ||
+ | djnz getpixoff_lop | ||
+ | getpixoff_norotate: | ||
+ | ; Ahora A es una máscara de pixel | ||
+ | ;--- Fin nuevo código --- | ||
+ | |||
+ | ret | ||
+ | </ | ||
\\ | \\ | ||
Línea 1010: | Línea 1006: | ||
<code z80> | <code z80> | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
pix_rotate_bit: | pix_rotate_bit: | ||
- | | + | |
- | | + | |
</ | </ | ||
- | La rutina pone A a cero y establece el Carry Flag a 1, por lo que la primera ejecución de RRA (que siempre se realizará) ubica el 1 del CF en el bit 7 de A. A continuación el DJNZ que se realiza " | + | La rutina pone A a cero y establece el Carry Flag a 1, por lo que la primera ejecución de '' |
\\ | \\ | ||
- | {{ : | + | {{ : |
\\ | \\ | ||
Línea 1036: | Línea 1032: | ||
; | ; | ||
Relative_to_Mask: | Relative_to_Mask: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
pix_rotate_bit: | pix_rotate_bit: | ||
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
Línea 1051: | Línea 1047: | ||
; Activar el pixel apuntado por HL usando la máscara A | ; Activar el pixel apuntado por HL usando la máscara A | ||
Plot_Pixel_HL: | Plot_Pixel_HL: | ||
- | | + | |
- | | + | |
- | | + | |
; Desactivar el pixel apuntado por HL usando la máscara A | ; Desactivar el pixel apuntado por HL usando la máscara A | ||
Unplot_Pixel_HL: | Unplot_Pixel_HL: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
; Testear el pixel apuntado por HL usando la máscara A | ; Testear el pixel apuntado por HL usando la máscara A | ||
Test_Pixel_HL: | Test_Pixel_HL: | ||
- | | + | |
- | | + | |
</ | </ | ||
Línea 1077: | Línea 1073: | ||
</ | </ | ||
- | Si ejecutaramos un simple | + | Si ejecutaramos un simple |
< | < | ||
Pixeles activos en (16384) = 10000001 | Pixeles activos en (16384) = 10000001 | ||
Máscara de pixel A = 00010000 | Máscara de pixel A = 00010000 | ||
- | OPERACION (HL)=A | + | OPERACION (HL)=A |
Resultado en (16384) | Resultado en (16384) | ||
</ | </ | ||
- | | + | |
< | < | ||
Pixeles activos en (16384) = 10000001 | Pixeles activos en (16384) = 10000001 | ||
Máscara de pixel A = 00010000 | Máscara de pixel A = 00010000 | ||
- | OPERACION A = A OR (HL) = OR (HL) | + | OPERACION A = A or (hl) = or (hl) |
Resultado en A = 10010001 | Resultado en A = 10010001 | ||
- | OPERACION (HL)=A | + | OPERACION (HL)=A |
Resultado en (16384) | Resultado en (16384) | ||
</ | </ | ||
- | Si en lugar de un OR hubieramos complementado A y hubieramos hecho un AND, habríamos puesto a 0 el bit (y por tanto el pixel): | + | Si en lugar de un '' |
< | < | ||
Pixeles activos en (16384) = 10000001 | Pixeles activos en (16384) = 10000001 | ||
Máscara de pixel A = 00010000 | Máscara de pixel A = 00010000 | ||
- | OPERACION A = CPL(A) = 11101111 | + | OPERACION A = cpl(A) = 11101111 |
- | OPERACION A = A OR (HL) = AND (HL) | + | OPERACION A = A or (hl) = and (hl) |
Resultado en A = 10000001 | Resultado en A = 10000001 | ||
- | OPERACION (HL)=A | + | OPERACION (HL)=A |
Resultado en (16384) | Resultado en (16384) | ||
</ | </ | ||
Línea 1112: | Línea 1108: | ||
<code z80> | <code z80> | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
La primera pregunta que nos planteamos es, si es imprescindible disponer de una máscara de pixel para dibujar o borrar píxeles, ¿por qué no incluir este código de rotación de A directamente en la rutina de coordenación? | La primera pregunta que nos planteamos es, si es imprescindible disponer de una máscara de pixel para dibujar o borrar píxeles, ¿por qué no incluir este código de rotación de A directamente en la rutina de coordenación? | ||
- | Si la rutina va a ser utilizada principalmente para trazar píxeles, resultará conveniente incorporar al final de Get_Pixel_Offset_HR() el cálculo de la máscara, y devolver en A dicha máscara en lugar de la posición relativa del pixel. | + | Si la rutina va a ser utilizada principalmente para trazar píxeles, resultará conveniente incorporar al final de '' |
Pero lo normal en el desarrollo de programas y juegos es que utilicemos la rutina de coordenación para obtener la posición inicial en la que comenzar a trazar sprites, bloques (del mapeado), fuentes de texto, marcadores. En ese caso es absurdo emplear " | Pero lo normal en el desarrollo de programas y juegos es que utilicemos la rutina de coordenación para obtener la posición inicial en la que comenzar a trazar sprites, bloques (del mapeado), fuentes de texto, marcadores. En ese caso es absurdo emplear " | ||
- | Por ese motivo, no hemos agregado esta pequeña porción de código a la rutina de Get_Pixel_Offset, | + | Por ese motivo, no hemos agregado esta pequeña porción de código a la rutina de '' |
Línea 1131: | Línea 1127: | ||
==== La rutina de la ROM PIXEL-ADDRESS ==== | ==== La rutina de la ROM PIXEL-ADDRESS ==== | ||
- | | + | |
<code z80> | <code z80> | ||
Línea 1144: | Línea 1140: | ||
; OUT: HL = address, A = pixel relative position in (HL) | ; OUT: HL = address, A = pixel relative position in (HL) | ||
- | $22AA PIXEL-ADD | + | $22aa PIXEL-ADD |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | $22B1 PIXEL_ADDRESS_B: | + | $22b1 PIXEL_ADDRESS_B: |
; hacia las 2 ultimas lineas de pantalla. | ; hacia las 2 ultimas lineas de pantalla. | ||
- | | + | |
- | | + | |
; 0b7b6b5b4b3b2b1. | ; 0b7b6b5b4b3b2b1. | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
- | Esta rutina tiene una serie de ventajas: Entrando por $22B1 tenemos 23 instrucciones (107 t-estados) que realizan el cálculo de la dirección de memoria además de la posición del pixel dentro del byte al que apunta dicha dirección. La rutina está ubicada en ROM, por lo que ahorramos esta pequeña porción de espacio en nuestro programa. Además, no usa la pila, no usa registros adicionales a B, C, HL y A, y no altera los valores de B y C durante el cálculo. | + | Esta rutina tiene una serie de ventajas: Entrando por $22b1 tenemos 23 instrucciones (107 t-estados) que realizan el cálculo de la dirección de memoria además de la posición del pixel dentro del byte al que apunta dicha dirección. La rutina está ubicada en ROM, por lo que ahorramos esta pequeña porción de espacio en nuestro programa. Además, no usa la pila, no usa registros adicionales a B, C, HL y A, y no altera los valores de B y C durante el cálculo. |
- | | + | |
<code z80> | <code z80> | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
Línea 1196: | Línea 1192: | ||
<code z80> | <code z80> | ||
- | | + | ; Ejemplo de uso de pixel-address (ROM) |
- | ORG 50000 | + | ORG 50000 |
- | PIXEL_ADDRESS EQU $22B1 | + | PIXEL_ADDRESS EQU $22b1 |
entrada: | entrada: | ||
; Imprimimos un solo pixel en (0,0) | ; Imprimimos un solo pixel en (0,0) | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
; Imprimimos 8 pixeles en (255,191) | ; Imprimimos 8 pixeles en (255,191) | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
; Imprimimos 4 pixeles en el centro de la pantalla | ; Imprimimos 4 pixeles en el centro de la pantalla | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | loop: ; Bucle para no volver a BASIC y que | + | loop: ; Bucle para no volver a BASIC y que |
- | | + | |
- | END 50000 | + | |
</ | </ | ||
Línea 1239: | Línea 1235: | ||
\\ | \\ | ||
- | | + | |
<code z80> | <code z80> | ||
- | PIXEL_ADDRESS EQU $22B1 | + | PIXEL_ADDRESS EQU $22b1 |
; | ; | ||
Línea 1250: | Línea 1246: | ||
; | ; | ||
PIXEL_ADDRESS_MASK: | PIXEL_ADDRESS_MASK: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
pix_rotate_bit: | pix_rotate_bit: | ||
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
Línea 1274: | 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 1318: | Línea 1314: | ||
DW $4060, $4160, $4260, $4360, $4460, $4560, $4660, $4760 | DW $4060, $4160, $4260, $4360, $4460, $4560, $4660, $4760 | ||
DW $4080, $4180, $4280, $4380, $4480, $4580, $4680, $4780 | DW $4080, $4180, $4280, $4380, $4480, $4580, $4680, $4780 | ||
- | DW $40A0, $41A0, $42A0, $43A0, $44A0, $45A0, $46A0, $47A0 | + | DW $40a0, $41a0, $42a0, $43a0, $44a0, $45a0, $46a0, $47a0 |
- | DW $40C0, $41C0, $42C0, $43C0, $44C0, $45C0, $46C0, $47C0 | + | DW $40c0, $41c0, $42c0, $43c0, $44c0, $45c0, $46c0, $47c0 |
- | DW $40E0, $41E0, $42E0, $43E0, $44E0, $45E0, $46E0, $47E0 | + | DW $40e0, $41e0, $42e0, $43e0, $44e0, $45e0, $46e0, $47e0 |
- | DW $4800, $4900, $4A00, $4B00, $4C00, $4D00, $4E00, $4F00 | + | DW $4800, $4900, $4a00, $4b00, $4c00, $4d00, $4e00, $4f00 |
- | DW $4820, $4920, $4A20, $4B20, $4C20, $4D20, $4E20, $4F20 | + | DW $4820, $4920, $4a20, $4b20, $4c20, $4d20, $4e20, $4f20 |
- | DW $4840, $4940, $4A40, $4B40, $4C40, $4D40, $4E40, $4F40 | + | DW $4840, $4940, $4a40, $4b40, $4c40, $4d40, $4e40, $4f40 |
- | DW $4860, $4960, $4A60, $4B60, $4C60, $4D60, $4E60, $4F60 | + | DW $4860, $4960, $4a60, $4b60, $4c60, $4d60, $4e60, $4f60 |
- | DW $4880, $4980, $4A80, $4B80, $4C80, $4D80, $4E80, $4F80 | + | DW $4880, $4980, $4a80, $4b80, $4c80, $4d80, $4e80, $4f80 |
- | DW $48A0, $49A0, $4AA0, $4BA0, $4CA0, $4DA0, $4EA0, $4FA0 | + | DW $48a0, $49a0, $4aa0, $4ba0, $4ca0, $4da0, $4ea0, $4fa0 |
- | DW $48C0, $49C0, $4AC0, $4BC0, $4CC0, $4DC0, $4EC0, $4FC0 | + | DW $48c0, $49c0, $4ac0, $4bc0, $4cc0, $4dc0, $4ec0, $4fc0 |
- | DW $48E0, $49E0, $4AE0, $4BE0, $4CE0, $4DE0, $4EE0, $4FE0 | + | DW $48e0, $49e0, $4ae0, $4be0, $4ce0, $4de0, $4ee0, $4fe0 |
DW $5000, $5100, $5200, $5300, $5400, $5500, $5600, $5700 | DW $5000, $5100, $5200, $5300, $5400, $5500, $5600, $5700 | ||
DW $5020, $5120, $5220, $5320, $5420, $5520, $5620, $5720 | DW $5020, $5120, $5220, $5320, $5420, $5520, $5620, $5720 | ||
Línea 1334: | Línea 1330: | ||
DW $5060, $5160, $5260, $5360, $5460, $5560, $5660, $5760 | DW $5060, $5160, $5260, $5360, $5460, $5560, $5660, $5760 | ||
DW $5080, $5180, $5280, $5380, $5480, $5580, $5680, $5780 | DW $5080, $5180, $5280, $5380, $5480, $5580, $5680, $5780 | ||
- | DW $50A0, $51A0, $52A0, $53A0, $54A0, $55A0, $56A0, $57A0 | + | DW $50a0, $51a0, $52a0, $53a0, $54a0, $55a0, $56a0, $57a0 |
- | DW $50C0, $51C0, $52C0, $53C0, $54C0, $55C0, $56C0, $57C0 | + | DW $50c0, $51c0, $52c0, $53c0, $54c0, $55c0, $56c0, $57c0 |
- | DW $50E0, $51E0, $52E0, $53E0, $54E0, $55E0, $56E0, $57E0 | + | DW $50e0, $51e0, $52e0, $53e0, $54e0, $55e0, $56e0, $57e0 |
</ | </ | ||
Línea 1360: | Línea 1356: | ||
</ | </ | ||
- | La tabla de valores DW estaría incorporada en nuestro programa y por tanto pasaría a formar parte del " | + | La tabla de valores |
Si por algún motivo no queremos incluir la tabla en el listado, podemos generarla en el arranque de nuestro programa en alguna posición de memoria libre o designada a tal efecto mediante la siguiente rutina: | Si por algún motivo no queremos incluir la tabla en el listado, podemos generarla en el arranque de nuestro programa en alguna posición de memoria libre o designada a tal efecto mediante la siguiente rutina: | ||
Línea 1370: | Línea 1366: | ||
; | ; | ||
- | Scanline_Offsets EQU $F900 | + | Scanline_Offsets EQU $f900 |
Generate_Scanline_Table: | Generate_Scanline_Table: | ||
- | | + | |
- | | + | |
- | | + | |
genscan_loop: | genscan_loop: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
; Recorremos los scanlines y bloques en un bucle generando las | ; Recorremos los scanlines y bloques en un bucle generando las | ||
; sucesivas direccione en DE para almacenarlas en la tabla. | ; sucesivas direccione en DE para almacenarlas en la tabla. | ||
; Cuando se cambia de caracter, scanline o tercio, se ajusta: | ; Cuando se cambia de caracter, scanline o tercio, se ajusta: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
genscan_nextline: | genscan_nextline: | ||
- | | + | |
- | | + | |
</ | </ | ||
Línea 1419: | Línea 1415: | ||
; | ; | ||
Get_Pixel_Offset_LUT_HR: | Get_Pixel_Offset_LUT_HR: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | ; Ahora Offset = [HL] | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | ; Ahora sumamos la X, para lo cual calculamos CCCCC | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
Línea 1445: | Línea 1441: | ||
<code z80> | <code z80> | ||
- | | + | ; Ejemplo de uso de LUT |
- | ORG 50000 | + | ORG 50000 |
entrada: | entrada: | ||
- | | + | |
- | | + | |
loop_draw: | loop_draw: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | loop: ; Bucle para no volver a BASIC y que | + | loop: ; Bucle para no volver a BASIC y que |
- | | + | |
+ | |||
+ | END 50000 | ||
</ | </ | ||
Línea 1479: | Línea 1477: | ||
==== Optimizando la lectura a través de tablas ==== | ==== Optimizando la lectura a través de tablas ==== | ||
- | El coste de ejecución de la rutina | + | El coste de ejecución de la rutina |
Una ingeniosa solución a este problema consiste en dividir la tabla de 192 direcciones de 16 bits en 2 tablas de 192 bytes cada una que almacenen la parte alta de la dirección en la primera de las tablas y la parte baja de la dirección en la segunda, de tal forma que: | Una ingeniosa solución a este problema consiste en dividir la tabla de 192 direcciones de 16 bits en 2 tablas de 192 bytes cada una que almacenen la parte alta de la dirección en la primera de las tablas y la parte baja de la dirección en la segunda, de tal forma que: | ||
Línea 1502: | Línea 1500: | ||
</ | </ | ||
- | El paso de una tabla a otra se realizará incrementando o decrementando la parte alta del registro de 16 bits (INC H o DEC H), gracias al hecho de que son 2 tablas múltiplos de 256 y consecutivas en memoria. | + | El paso de una tabla a otra se realizará incrementando o decrementando la parte alta del registro de 16 bits (inc h o dec h), gracias al hecho de que son 2 tablas múltiplos de 256 y consecutivas en memoria. |
| | ||
Línea 1522: | Línea 1520: | ||
Generate_Scanline_Table_Aligned: | Generate_Scanline_Table_Aligned: | ||
- | | + | |
- | | + | |
- | | + | |
genscan_loop: | genscan_loop: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
; Recorremos los scanlines y bloques en un bucle generando las | ; Recorremos los scanlines y bloques en un bucle generando las | ||
; sucesivas direccione en DE para almacenarlas en la tabla. | ; sucesivas direccione en DE para almacenarlas en la tabla. | ||
; Cuando se cambia de caracter, scanline o tercio, se ajusta: | ; Cuando se cambia de caracter, scanline o tercio, se ajusta: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
genscan_nextline: | genscan_nextline: | ||
- | | + | |
- | | + | |
</ | </ | ||
Línea 1557: | Línea 1555: | ||
Estos 64 bytes no se utilizan en la rutina de generación ni (como veremos a continuación) en la de cálculo, por lo que podemos aprovecharlos para ubicar variables de nuestro programa, tablas temporales, etc, y así no desperdiciarlos. | Estos 64 bytes no se utilizan en la rutina de generación ni (como veremos a continuación) en la de cálculo, por lo que podemos aprovecharlos para ubicar variables de nuestro programa, tablas temporales, etc, y así no desperdiciarlos. | ||
- | Si necesitaramos reservar espacio en nuestro programa para después generar la tabla sobre él, podemos hacerlo mediante las directivas de preprocesado del ensamblador ORG (Origen) y DS (Define Space). Las siguientes líneas (ubicadas al final del fichero de código) reservan en nuestro programa un array de 448 bytes de longitud y tamaño cero alineado en una posición múltiplo de 256: | + | Si necesitaramos reservar espacio en nuestro programa para después generar la tabla sobre él, podemos hacerlo mediante las directivas de preprocesado del ensamblador |
<code z80> | <code z80> | ||
- | ORG 64000 | + | |
Scanline_Offsets: | Scanline_Offsets: | ||
Línea 1569: | Línea 1567: | ||
< | < | ||
- | ; Macro de alineacion para PASMO | + | |
- | align macro value | + | align macro value |
if $ mod value | if $ mod value | ||
ds value - ($ mod value) | ds value - ($ mod value) | ||
Línea 1576: | Línea 1574: | ||
endm | endm | ||
- | + | | |
- | align 256 | + | |
Scanline_Offsets: | Scanline_Offsets: | ||
Línea 1584: | Línea 1581: | ||
DB $20, $20, $20, $20, $40, $40, $40, $40, $40, $40, $40, $40 | DB $20, $20, $20, $20, $40, $40, $40, $40, $40, $40, $40, $40 | ||
DB $60, $60, $60, $60, $60, $60, $60, $60, $80, $80, $80, $80 | DB $60, $60, $60, $60, $60, $60, $60, $60, $80, $80, $80, $80 | ||
- | DB $80, $80, $80, $80, $A0, $A0, $A0, $A0, $A0, $A0, $A0, $A0 | + | DB $80, $80, $80, $80, $a0, $a0, $a0, $a0, $a0, $a0, $a0, $a0 |
- | DB $C0, $C0, $C0, $C0, $C0, $C0, $C0, $C0, $E0, $E0, $E0, $E0 | + | DB $c0, $c0, $c0, $c0, $c0, $c0, $c0, $c0, $e0, $e0, $e0, $e0 |
- | DB $E0, $E0, $E0, $E0, $00, $00, $00, $00, $00, $00, $00, $00 | + | DB $e0, $e0, $e0, $e0, $00, $00, $00, $00, $00, $00, $00, $00 |
DB $20, $20, $20, $20, $20, $20, $20, $20, $40, $40, $40, $40 | DB $20, $20, $20, $20, $20, $20, $20, $20, $40, $40, $40, $40 | ||
DB $40, $40, $40, $40, $60, $60, $60, $60, $60, $60, $60, $60 | DB $40, $40, $40, $40, $60, $60, $60, $60, $60, $60, $60, $60 | ||
- | DB $80, $80, $80, $80, $80, $80, $80, $80, $A0, $A0, $A0, $A0 | + | DB $80, $80, $80, $80, $80, $80, $80, $80, $a0, $a0, $a0, $a0 |
- | DB $A0, $A0, $A0, $A0, $C0, $C0, $C0, $C0, $C0, $C0, $C0, $C0 | + | DB $a0, $a0, $a0, $a0, $c0, $c0, $c0, $c0, $c0, $c0, $c0, $c0 |
- | DB $E0, $E0, $E0, $E0, $E0, $E0, $E0, $E0, $00, $00, $00, $00 | + | DB $e0, $e0, $e0, $e0, $e0, $e0, $e0, $e0, $00, $00, $00, $00 |
DB $00, $00, $00, $00, $20, $20, $20, $20, $20, $20, $20, $20 | DB $00, $00, $00, $00, $20, $20, $20, $20, $20, $20, $20, $20 | ||
DB $40, $40, $40, $40, $40, $40, $40, $40, $60, $60, $60, $60 | DB $40, $40, $40, $40, $40, $40, $40, $40, $60, $60, $60, $60 | ||
DB $60, $60, $60, $60, $80, $80, $80, $80, $80, $80, $80, $80 | DB $60, $60, $60, $60, $80, $80, $80, $80, $80, $80, $80, $80 | ||
- | DB $A0, $A0, $A0, $A0, $A0, $A0, $A0, $A0, $C0, $C0, $C0, $C0 | + | DB $a0, $a0, $a0, $a0, $a0, $a0, $a0, $a0, $c0, $c0, $c0, $c0 |
- | DB $C0, $C0, $C0, $C0, $E0, $E0, $E0, $E0, $E0, $E0, $E0, $E0 | + | DB $c0, $c0, $c0, $c0, $e0, $e0, $e0, $e0, $e0, $e0, $e0, $e0 |
Free_64_Bytes: | Free_64_Bytes: | ||
Línea 1610: | Línea 1607: | ||
DB $44, $45, $46, $47, $40, $41, $42, $43, $44, $45, $46, $47 | DB $44, $45, $46, $47, $40, $41, $42, $43, $44, $45, $46, $47 | ||
DB $40, $41, $42, $43, $44, $45, $46, $47, $40, $41, $42, $43 | DB $40, $41, $42, $43, $44, $45, $46, $47, $40, $41, $42, $43 | ||
- | DB $44, $45, $46, $47, $48, $49, $4A, $4B, $4C, $4D, $4E, $4F | + | DB $44, $45, $46, $47, $48, $49, $4a, $4b, $4c, $4d, $4e, $4f |
- | DB $48, $49, $4A, $4B, $4C, $4D, $4E, $4F, $48, $49, $4A, $4B | + | DB $48, $49, $4a, $4b, $4c, $4d, $4e, $4f, $48, $49, $4a, $4b |
- | DB $4C, $4D, $4E, $4F, $48, $49, $4A, $4B, $4C, $4D, $4E, $4F | + | DB $4c, $4d, $4e, $4f, $48, $49, $4a, $4b, $4c, $4d, $4e, $4f |
- | DB $48, $49, $4A, $4B, $4C, $4D, $4E, $4F, $48, $49, $4A, $4B | + | DB $48, $49, $4a, $4b, $4c, $4d, $4e, $4f, $48, $49, $4a, $4b |
- | DB $4C, $4D, $4E, $4F, $48, $49, $4A, $4B, $4C, $4D, $4E, $4F | + | DB $4c, $4d, $4e, $4f, $48, $49, $4a, $4b, $4c, $4d, $4e, $4f |
- | DB $48, $49, $4A, $4B, $4C, $4D, $4E, $4F, $50, $51, $52, $53 | + | DB $48, $49, $4a, $4b, $4c, $4d, $4e, $4f, $50, $51, $52, $53 |
DB $54, $55, $56, $57, $50, $51, $52, $53, $54, $55, $56, $57 | DB $54, $55, $56, $57, $50, $51, $52, $53, $54, $55, $56, $57 | ||
DB $50, $51, $52, $53, $54, $55, $56, $57, $50, $51, $52, $53 | DB $50, $51, $52, $53, $54, $55, $56, $57, $50, $51, $52, $53 | ||
Línea 1634: | Línea 1631: | ||
; | ; | ||
Get_Pixel_Offset_LUT_2: | Get_Pixel_Offset_LUT_2: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
- | El coste de ejecución de esta rutina es de 77 t-estados, incluyendo el RET, la conversión de " | + | El coste de ejecución de esta rutina es de 77 t-estados, incluyendo el '' |
\\ | \\ | ||
Línea 1695: | Línea 1692: | ||
Pixel_Izquierda_HL_Mask: | Pixel_Izquierda_HL_Mask: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
Pixel_Derecha_HL_Mask: | Pixel_Derecha_HL_Mask: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
Son apenas 4 instrucciones, | Son apenas 4 instrucciones, | ||
- | | + | |
Si en lugar de una máscara de pixel tenemos en A la posición relativa (0-7), podemos utilizar el siguiente código: | Si en lugar de una máscara de pixel tenemos en A la posición relativa (0-7), podemos utilizar el siguiente código: | ||
Línea 1718: | Línea 1715: | ||
Pixel_Derecha_HL_Rel: | Pixel_Derecha_HL_Rel: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
Pixel_Izquierda_HL_Rel: | Pixel_Izquierda_HL_Rel: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
Línea 1750: | Línea 1747: | ||
<code z80> | <code z80> | ||
; Avanzamos HL 1 scanline: | ; Avanzamos HL 1 scanline: | ||
- | | + | |
- | | + | |
- | | + | |
- | ; es porque era 111b y ahora 1000b. | + | |
- | | + | |
- | | + | |
- | ; caracter al 0 del siguiente: ajustar NNN | + | |
- | | + | |
- | | + | |
- | | + | |
- | ; tercio, pero ya lo hizo el INC H (111b -> 1000b) | + | |
- | | + | |
- | | + | |
- | | + | |
nofix_abajop: | nofix_abajop: | ||
Línea 1773: | Línea 1770: | ||
<code z80> | <code z80> | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | Anterior_SL_DEC: | + | Anterior_SL_DEC: |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
- | | + | |
Línea 1804: | Línea 1801: | ||
; | ; | ||
Siguiente_Scanline_HL: | Siguiente_Scanline_HL: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
- | La rutina para retroceder al scanline superior es de similar factura, con una pequeña reorganización del código para evitar el salto con JR: | + | La rutina para retroceder al scanline superior es de similar factura, con una pequeña reorganización del código para evitar el salto con '' |
Línea 1833: | Línea 1830: | ||
; | ; | ||
Anterior_Scanline_HL: | Anterior_Scanline_HL: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
- | Siguiente_Scanline_HL será especialmente útil en el desarrollo de rutinas de impresión de Sprites, aunque lo normal es que incluyamos el código " | + | La rutina '' |
Línea 1871: | Línea 1868: | ||
; | ; | ||
Attr_Offset_From_Image: | Attr_Offset_From_Image: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
Línea 1892: | Línea 1889: | ||
; | ; | ||
Image_Offset_From_Attr: | Image_Offset_From_Attr: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
Línea 1915: | Línea 1912: | ||
; | ; | ||
Get_Char_Data: | Get_Char_Data: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
| | ||
+ | |||
+ | \\ | ||
+ | ===== 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 1955: | Línea 2094: | ||
* [[http:// | * [[http:// | ||
* [[http:// | * [[http:// | ||
+ | * [[https:// | ||
\\ | \\ | ||
**[ [[.: | **[ [[.: | ||