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:gfx1_vram [08-01-2024 09:34] – [Efectos sobre la imagen y los atributos] sromero | cursos:ensamblador:gfx1_vram [21-01-2024 18:43] (actual) – [Efectos sobre la imagen y los atributos] sromero | ||
---|---|---|---|
Línea 79: | Línea 79: | ||
===== La videomemoria del Spectrum ===== | ===== La videomemoria del Spectrum ===== | ||
- | | + | |
Este área de aprox. 7 KB de memoria es donde podemos encontrar la representación digital de la imagen que estamos viendo en el monitor y que la ULA lee regularmente para poder generar la señal de vídeo que requiere el retrazar la imagen. | Este área de aprox. 7 KB de memoria es donde podemos encontrar la representación digital de la imagen que estamos viendo en el monitor y que la ULA lee regularmente para poder generar la señal de vídeo que requiere el retrazar la imagen. | ||
Línea 133: | Línea 133: | ||
ORG 50000 | ORG 50000 | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | END 50000 | + | |
+ | | ||
</ | </ | ||
Línea 190: | Línea 191: | ||
\\ | \\ | ||
- | * **El área de imagen**: Es el área de memoria que va desde $4000 (16384) hasta $57FF (22527). Este área de memoria de 6 KB almacena la información gráfica de 256x192 píxeles, donde cada byte (de 8 bits) define el estado de 8 píxeles (en cada bit del byte se tiene el estado de un pixel, con 1=activo, 0=no activo), de forma que se puede codificar cada línea de 256 pixeles con 256/8=32 bytes. Utilizando 32 bytes por línea, podemos almacenar el estado de una pantalla completa con 32*192 = 6144 bytes = 6 KB de memoria. Por ejemplo, la celdilla de memoria 16384 contiene el estado de los 8 primeros píxeles de la línea 0 de la pantalla, desde (0,0) a (7,0). | + | * **El área de imagen**: Es el área de memoria que va desde $4000 (16384) hasta $57ff (22527). Este área de memoria de 6 KB almacena la información gráfica de 256x192 píxeles, donde cada byte (de 8 bits) define el estado de 8 píxeles (en cada bit del byte se tiene el estado de un pixel, con 1=activo, 0=no activo), de forma que se puede codificar cada línea de 256 pixeles con 256/8=32 bytes. Utilizando 32 bytes por línea, podemos almacenar el estado de una pantalla completa con 32*192 = 6144 bytes = 6 KB de memoria. Por ejemplo, la celdilla de memoria 16384 contiene el estado de los 8 primeros píxeles de la línea 0 de la pantalla, desde (0,0) a (7,0). |
- | * **El área de atributos**: | + | * **El área de atributos**: |
\\ | \\ | ||
Línea 224: | Línea 225: | ||
<code basic> | <code basic> | ||
10 BORDER 1: PAPER 1: INK 7: CLS | 10 BORDER 1: PAPER 1: INK 7: CLS | ||
- | 20 FOR R = 10 TO 70 STEP 10 : CIRCLE 128, 96, R : NEXT R | + | 20 FOR r = 10 TO 70 STEP 10 : CIRCLE 128, 96, R : NEXT R |
30 PAUSE 0 | 30 PAUSE 0 | ||
40 INK 2 : PLOT 30, 30 : DRAW 220, 120 | 40 INK 2 : PLOT 30, 30 : DRAW 220, 120 | ||
Línea 235: | Línea 236: | ||
\\ | \\ | ||
- | A continuación pulsamos una tecla y se ejecuta el "INK 2 + PLOT + DRAW" | + | A continuación pulsamos una tecla y se ejecuta el '' |
\\ | \\ | ||
Línea 283: | Línea 284: | ||
===== Videomemoria: | ===== Videomemoria: | ||
- | El área de imagen del Spectrum es el bloque de 6144 bytes (6KB) entre 16384 ($4000) y 22527 ($57FF). Cada una de las posiciones de memoria de este área almacenan la información de imagen (estado de los píxeles) de 8 píxeles de pantalla consecutivos, | + | El área de imagen del Spectrum es el bloque de 6144 bytes (6KB) entre 16384 ($4000) y 22527 ($57ff). Cada una de las posiciones de memoria de este área almacenan la información de imagen (estado de los píxeles) de 8 píxeles de pantalla consecutivos, |
Como veremos cuando hablemos del área de atributos, que los píxeles estén a ON o a OFF no implica que la ULA sólo dibuje los píxeles activos. Si el pixel está activo (bit a 1), la ULA lo traza en pantalla utilizando el color de tinta actual que corresponda a ese píxel mientras que un bit a 0 significa que el pixel no está encendido y que la ULA debe de dibujarlo con el color de papel actual. | Como veremos cuando hablemos del área de atributos, que los píxeles estén a ON o a OFF no implica que la ULA sólo dibuje los píxeles activos. Si el pixel está activo (bit a 1), la ULA lo traza en pantalla utilizando el color de tinta actual que corresponda a ese píxel mientras que un bit a 0 significa que el pixel no está encendido y que la ULA debe de dibujarlo con el color de papel actual. | ||
Línea 333: | Línea 334: | ||
<code basic> | <code basic> | ||
10 CLS | 10 CLS | ||
- | 20 FOR I=0 TO 31 : POKE 16384+I, 170 : NEXT I | + | 20 FOR i=0 TO 31 : POKE 16384+I, 170 : NEXT I |
30 PAUSE 0 | 30 PAUSE 0 | ||
</ | </ | ||
Línea 355: | Línea 356: | ||
<code basic> | <code basic> | ||
10 CLS | 10 CLS | ||
- | 20 FOR I=0 TO 63 : POKE 16384+I, 170 : NEXT I | + | 20 FOR i=0 TO 63 : POKE 16384+I, 170 : NEXT I |
30 PAUSE 0 | 30 PAUSE 0 | ||
</ | </ | ||
Línea 386: | Línea 387: | ||
* (etc...) | * (etc...) | ||
- | Así hasta el byte 18331 o $47FF (cuando hemos avanzado 32*8*8 | + | Así hasta el byte 18331 o $47ff (cuando hemos avanzado 32*8*8 |
\\ | \\ | ||
Línea 395: | Línea 396: | ||
\\ | \\ | ||
- | | + | |
\\ | \\ | ||
- | * **Primer tercio**: Los 2 primeros KB de la videoram (de $4000 a $47FF) cubren los datos gráficos de los primeros 64 scanlines de la pantalla (líneas 0 a 7). | + | * **Primer tercio**: Los 2 primeros KB de la videoram (de $4000 a $47ff) cubren los datos gráficos de los primeros 64 scanlines de la pantalla (líneas 0 a 7). |
- | * **Segundo tercio**: Los siguientes 2KB de la videoram (de $4800 a $4FFF) cubren los datos gráficos de los siguientes 64 scanlines de la pantalla (líneas 8 a 15). | + | * **Segundo tercio**: Los siguientes 2KB de la videoram (de $4800 a $4fff) cubren los datos gráficos de los siguientes 64 scanlines de la pantalla (líneas 8 a 15). |
- | * **Tercer tercio**: Los siguientes 2KB de la videoram (de $5000 a $57FF) cubren los datos gráficos de los últimos 64 scanlines de la pantalla (líneas 16 a 23). | + | * **Tercer tercio**: Los siguientes 2KB de la videoram (de $5000 a $57ff) cubren los datos gráficos de los últimos 64 scanlines de la pantalla (líneas 16 a 23). |
\\ | \\ | ||
Línea 418: | Línea 419: | ||
Con el programa de ejemplo del apartado // | Con el programa de ejemplo del apartado // | ||
- | | + | |
<code z80> | <code z80> | ||
Línea 426: | Línea 427: | ||
; | ; | ||
ClearScreen: | ClearScreen: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
; porque ya hemos escrito en 16384. | ; porque ya hemos escrito en 16384. | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
De esta forma, podemos llamar a nuestra rutina ClearScreen colocando en A el patron con el que rellenar la pantalla, que puede ser 0 para " | De esta forma, podemos llamar a nuestra rutina ClearScreen colocando en A el patron con el que rellenar la pantalla, que puede ser 0 para " | ||
- | Los PUSH y POP están puestos para preservar los valores de los registros, pero podemos quitarlos si vamos a llamar a esta función siempre de forma controlada y no queremos preservarlos (o se pueden preservar antes de llamarla). | + | |
Línea 466: | Línea 467: | ||
; Mostrando la organizacion de la videomemoria | ; Mostrando la organizacion de la videomemoria | ||
- | | + | |
; Pseudocodigo del programa: | ; Pseudocodigo del programa: | ||
; | ; | ||
Línea 478: | Línea 480: | ||
Start: | Start: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
bucle_192_lineas: | bucle_192_lineas: | ||
- | | + | |
; bucle exterior (usaremos B ahora en otro) | ; bucle exterior (usaremos B ahora en otro) | ||
- | | + | |
- | | + | |
- | | + | |
bucle_32_bytes: | bucle_32_bytes: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
; | ; | ||
Línea 509: | Línea 511: | ||
; | ; | ||
ClearScreen: | ClearScreen: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | INCLUDE " | + | |
- | END 50000 | + | |
</ | </ | ||
Línea 535: | Línea 537: | ||
| | ||
- | Es probable que la pauta de rellenado de la pantalla de nuestro ejemplo le resulte más que familiar al lector: efectivamente, | + | Es probable que la pauta de rellenado de la pantalla de nuestro ejemplo le resulte más que familiar al lector: efectivamente, |
La lectura secuencial desde cinta y su escritura lineal en videomemoria resulta en la carga de los datos gráficos en el mismo orden de scanlines en que nuestro programa de ejemplo ha rellenado la pantalla, seguida de la carga de los atributos, que en un rápido avance (sólo 768 bytes a cargar desde cinta) dotaba a la pantalla de carga de su color. | La lectura secuencial desde cinta y su escritura lineal en videomemoria resulta en la carga de los datos gráficos en el mismo orden de scanlines en que nuestro programa de ejemplo ha rellenado la pantalla, seguida de la carga de los atributos, que en un rápido avance (sólo 768 bytes a cargar desde cinta) dotaba a la pantalla de carga de su color. | ||
- | Del mismo modo, un simple | + | Del mismo modo, un simple |
- | | + | |
- | Este concepto, el de Pantalla Virtual, resulta muy interesante: | + | Este concepto, el de Pantalla Virtual, resulta muy interesante: |
Línea 564: | Línea 566: | ||
| 7 | $4700 | | | 7 | $4700 | | ||
- | Tal y como está organizada la videoram, basta con calcular la dirección de inicio del bloque en baja resolución donde queremos trazar un carácter, imprimir los 8 píxeles que forman su scanline (con la escritura de un único byte en videomemoria), | + | Tal y como está organizada la videoram, basta con calcular la dirección de inicio del bloque en baja resolución donde queremos trazar un carácter, imprimir los 8 píxeles que forman su scanline (con la escritura de un único byte en videomemoria), |
| | ||
Línea 572: | Línea 574: | ||
===== Videomemoria: | ===== Videomemoria: | ||
- | El área de atributos es el bloque de 768 bytes entre $5800 (22528) y $5AFF (23295), ambas celdillas de memoria incluídas. Cada una de las posiciones de memoria de este área almacenan la información de color (color de tinta, color de papel, brillo y flash) de un bloque de 8x8 píxeles en la pantalla. | + | El área de atributos es el bloque de 768 bytes entre $5800 (22528) y $5aff (23295), ambas celdillas de memoria incluídas. Cada una de las posiciones de memoria de este área almacenan la información de color (color de tinta, color de papel, brillo y flash) de un bloque de 8x8 píxeles en la pantalla. |
El tamaño de 768 bytes de este área viene determinado por la resolución del sistema de color del Spectrum: Hemos dicho que el sistema gráfico dispone de una resolución de 256x192, pero el sistema de color divide la pantalla en bloques de 8x8 píxeles, lo que nos da una resolución de color de 256/8 x 192/8 = 32x24 bloques. Como la información de color de cada bloque se codifica en un único byte, para almacenar la información de color de toda una pantalla se requieren 32 x 24 x 1 = 768 bytes. | El tamaño de 768 bytes de este área viene determinado por la resolución del sistema de color del Spectrum: Hemos dicho que el sistema gráfico dispone de una resolución de 256x192, pero el sistema de color divide la pantalla en bloques de 8x8 píxeles, lo que nos da una resolución de color de 256/8 x 192/8 = 32x24 bloques. Como la información de color de cada bloque se codifica en un único byte, para almacenar la información de color de toda una pantalla se requieren 32 x 24 x 1 = 768 bytes. | ||
Línea 587: | Línea 589: | ||
\\ | \\ | ||
- | Se puede decir que el área de atributos es totalmente lineal; consta de 768 bytes que se corresponden de forma consecutiva con el estado de cada bloque y de cada fila horizontal de bloques de pantalla: Los primeros 32 bytes del área se corresponden con la primera fila horizontal de bloques, los siguientes 32 bytes con la segunda, los siguientes 32 bytes con la tercera, hasta los últimos 32 bytes, que se corresponden con los de la línea 23. El byte alojado en la última posición ($5AFF) se corresponde con el atributo del bloque (31,23). | + | Se puede decir que el área de atributos es totalmente lineal; consta de 768 bytes que se corresponden de forma consecutiva con el estado de cada bloque y de cada fila horizontal de bloques de pantalla: Los primeros 32 bytes del área se corresponden con la primera fila horizontal de bloques, los siguientes 32 bytes con la segunda, los siguientes 32 bytes con la tercera, hasta los últimos 32 bytes, que se corresponden con los de la línea 23. El byte alojado en la última posición ($5aff) se corresponde con el atributo del bloque (31,23). |
A continuación podemos ver una tabla que muestra los inicios y fin de cada línea de atributos en pantalla: | A continuación podemos ver una tabla que muestra los inicios y fin de cada línea de atributos en pantalla: | ||
Línea 593: | Línea 595: | ||
|< 50% >| | |< 50% >| | ||
^ Línea ^ Inicio (carácter 0,N) ^ Fin (carácter 31,N) ^ | ^ Línea ^ Inicio (carácter 0,N) ^ Fin (carácter 31,N) ^ | ||
- | | 0 | $5800 | $581F | | + | | 0 | $5800 | $581f | |
- | | 1 | $5820 | $583F | | + | | 1 | $5820 | $583f | |
- | | 2 | $5860 | $585F | | + | | 2 | $5860 | $585f | |
- | | 3 | $5840 | $587F | | + | | 3 | $5840 | $587f | |
- | | 4 | $5880 | $589F | | + | | 4 | $5880 | $589f | |
- | | 5 | $58A0 | $58BF | | + | | 5 | $58a0 | $58bf | |
- | | 6 | $58C0 | $58DF | | + | | 6 | $58c0 | $58df | |
- | | 7 | $58E0 | $58FF | | + | | 7 | $58e0 | $58ff | |
- | | 8 | $5900 | $591F | | + | | 8 | $5900 | $591f | |
- | | 9 | $5920 | $593F | | + | | 9 | $5920 | $593f | |
- | | 10 | $5940 | $595F | | + | | 10 | $5940 | $595f | |
- | | 11 | $5960 | $597F | | + | | 11 | $5960 | $597f | |
- | | 12 | $5980 | $599F | | + | | 12 | $5980 | $599f | |
- | | 13 | $59A0 | $59BF | | + | | 13 | $59a0 | $59bf | |
- | | 14 | $59C0 | $59DF | | + | | 14 | $59c0 | $59df | |
- | | 15 | $59E0 | $59FF | | + | | 15 | $59e0 | $59ff | |
- | | 16 | $5A00 | $5A1F | | + | | 16 | $5a00 | $5a1f | |
- | | 17 | $5A20 | $5A3F | | + | | 17 | $5a20 | $5a3f | |
- | | 18 | $5A40 | $5A5F | | + | | 18 | $5a40 | $5a5f | |
- | | 19 | $5A60 | $5A7F | | + | | 19 | $5a60 | $5a7f | |
- | | 20 | $5A80 | $5A9F | | + | | 20 | $5a80 | $5a9f | |
- | | 21 | $5AA0 | $5ABF | | + | | 21 | $5aa0 | $5abf | |
- | | 22 | $5AC0 | $5ADF | | + | | 22 | $5ac0 | $5adf | |
- | | 23 | $5AE0 | $5AFF | | + | | 23 | $5ae0 | $5aff | |
Esta organización del área de atributos es muy sencilla y permite un cálculo muy sencillo de la posición de memoria del atributo de un bloque concreto de pantalla. Es decir, podemos encontrar fácilmente la posición de memoria que almacena el atributo que corresponde a un bloque concreto en baja resolución de pantalla mediante: | Esta organización del área de atributos es muy sencilla y permite un cálculo muy sencillo de la posición de memoria del atributo de un bloque concreto de pantalla. Es decir, podemos encontrar fácilmente la posición de memoria que almacena el atributo que corresponde a un bloque concreto en baja resolución de pantalla mediante: | ||
Línea 720: | Línea 722: | ||
<code z80> | <code z80> | ||
- | | + | ; Mostrando la organizacion de la videomemoria (atributos) |
- | ORG 50000 | + | ORG 50000 |
; Pseudocodigo del programa: | ; Pseudocodigo del programa: | ||
Línea 734: | Línea 736: | ||
Start: | Start: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
bucle_lineas: | bucle_lineas: | ||
- | | + | |
; bucle exterior (usaremos B ahora en otro) | ; bucle exterior (usaremos B ahora en otro) | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
no_resetear_papel: | no_resetear_papel: | ||
- | | + | |
- | | + | |
- | | + | |
bucle_32_bytes: | bucle_32_bytes: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
papel DEFB | papel DEFB | ||
- | |||
; | ; | ||
Línea 782: | Línea 783: | ||
; | ; | ||
ClearScreen: | ClearScreen: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | INCLUDE " | + | |
- | END 50000 | + | |
</ | </ | ||
Línea 805: | Línea 806: | ||
La memoria de atributos difiere de la de imagen en cuanto a que es totalmente lineal y que cada byte representa al bloque inmediatamente siguiente. Al llegar a la esquina derecha de la pantalla, el siguiente byte se corresponde con el primero de la siguiente línea. | La memoria de atributos difiere de la de imagen en cuanto a que es totalmente lineal y que cada byte representa al bloque inmediatamente siguiente. Al llegar a la esquina derecha de la pantalla, el siguiente byte se corresponde con el primero de la siguiente línea. | ||
- | |||
Con esta información, | Con esta información, | ||
Línea 816: | Línea 816: | ||
; | ; | ||
ClearAttributes: | ClearAttributes: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
; porque ya hemos escrito en 22528. | ; porque ya hemos escrito en 22528. | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
- | Dado lo habitual que puede ser llamar a ClearScreen y ClearAttributes, | + | Dado lo habitual que puede ser llamar a '' |
<code z80> | <code z80> | ||
Línea 840: | Línea 840: | ||
; | ; | ||
ClearScreenAttrib: | ClearScreenAttrib: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
Línea 874: | Línea 874: | ||
El borde tiene un color único que la ULA utiliza para retrazar todos y cada uno de los píxeles de este marco. Podemos cambiar este color accediendo en el Z80 al puerto de la ULA que controla el borde. | El borde tiene un color único que la ULA utiliza para retrazar todos y cada uno de los píxeles de este marco. Podemos cambiar este color accediendo en el Z80 al puerto de la ULA que controla el borde. | ||
- | El conocido comando de BASIC "BORDER" | + | El conocido comando de BASIC '' |
- | | + | |
- | En el capítulo dedicado a los Puertos de Entrada / Salida pudimos ya observar un ejemplo de cambio de color del borde, que ahora vamos a modificar para separar el OUT en una función | + | En el capítulo dedicado a los Puertos de Entrada / Salida pudimos ya observar un ejemplo de cambio de color del borde, que ahora vamos a modificar para separar el OUT en una función |
<code z80> | <code z80> | ||
; Cambio del color del borde al pulsar espacio | ; Cambio del color del borde al pulsar espacio | ||
- | | + | |
- | | + | |
start: | start: | ||
bucle: | bucle: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
suelta_tecla: | suelta_tecla: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
salir: | salir: | ||
- | | + | |
; | ; | ||
Línea 914: | Línea 914: | ||
; | ; | ||
SetBorder: | SetBorder: | ||
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
Línea 926: | Línea 926: | ||
\\ | \\ | ||
- | Si por algún motivo necesitaramos actualizar la variable del sistema BORDCR (porque vayamos a llamar a rutinas de la ROM que lo puedan manipular), bastará con modificar SetBorder para que almacene el valor del borde en la posición de memoria (23624) colocando primero el valor 0-7 en la posición de bits de PAPEL y estableciendo la tinta a negro si el brillo está activo: | + | Si por algún motivo necesitaramos actualizar la variable del sistema |
<code z80> | <code z80> | ||
Línea 934: | Línea 934: | ||
; | ; | ||
SetBorder: | SetBorder: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
; Si es bright | ; Si es bright | ||
- | | + | |
SetBorder_fin: | SetBorder_fin: | ||
- | | + | |
- | | + | |
</ | </ | ||
- | | + | |
| | ||
Línea 955: | Línea 955: | ||
<code z80> | <code z80> | ||
; Cambio del color del borde mientras la ULA dibuja | ; Cambio del color del borde mientras la ULA dibuja | ||
- | | + | |
- | | + | |
start: | start: | ||
bucle: | bucle: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
salir: | salir: | ||
- | | + | |
+ | |||
+ | END 50000 | ||
</ | </ | ||
Línea 982: | Línea 984: | ||
<code basic> | <code basic> | ||
- | 10 FOR I=0 TO 7 : BORDER I : NEXT I : GOTO 10 | + | 10 FOR i=0 TO 7 : BORDER I : NEXT I : GOTO 10 |
</ | </ | ||
Línea 991: | Línea 993: | ||
\\ | \\ | ||
- | Cabe destacar que en esta ocasión BASIC es todavía más rápido de lo normal pues la ejecución de BORDER I acaba resultando en la llamada a la función de la ROM "BORDER" | + | Cabe destacar que en esta ocasión BASIC es todavía más rápido de lo normal pues la ejecución de '' |
\\ | \\ | ||
===== El " | ===== El " | ||
- | Ahora que conocemos el formato de una celdilla de atributo podemos hablar de la variable del sistema ATTR-T (dirección de memoria **$5C8F** o **23695**), la cual almacena el atributo actual temporal que las rutinas de la ROM del Spectrum como nuestra conocida | + | Ahora que conocemos el formato de una celdilla de atributo podemos hablar de la variable del sistema |
- | A continuación tenemos un ejemplo que imprime cadenas con diferentes atributos de color. Para ello se ha creado una rutina PrintString basada en imprimir caracteres mediante | + | A continuación tenemos un ejemplo que imprime cadenas con diferentes atributos de color. Para ello se ha creado una rutina PrintString basada en imprimir caracteres mediante |
<code z80> | <code z80> | ||
; Prueba ATTR-P | ; Prueba ATTR-P | ||
- | | + | |
Start: | Start: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | ATTR_T | + | ATTR_T |
; | ; | ||
; Datos | ; Datos | ||
; | ; | ||
- | linea1: DEFB ' | + | linea1 |
- | linea2: DEFB 'Esto es una prueba', | + | linea2 |
- | INCLUDE " | + | |
- | END 50000 | + | |
</ | </ | ||
- | Con nuestra nueva rutina de PrintString trazaremos en pantalla 1 línea con los atributos actuales seguida de 2 líneas con diferentes atributos. Nótese como RST 16 entiende e interpreta en las cadenas los códigos de control como por ejemplo 13 (retorno de carro). | + | Con nuestra nueva rutina de '' |
\\ | \\ | ||
Línea 1059: | Línea 1061: | ||
===== Efectos sobre la imagen y los atributos ===== | ===== Efectos sobre la imagen y los atributos ===== | ||
- | Ahora ya conocemos la organización de la zona de imagen y atributos y sabemos (del capítulo sobre rutinas de SAVE/LOAD) cargar en ella datos gráficos desde cinta o incluir los datos gráficos en nuestro propio programa y volcarlos con instrucciones LDIR. Estamos pues en disposición de realizar pequeñas y sencillas rutinas de borrado de pantalla o de aparición de los datos en la misma de diferentes formas, como por ejemplo: | + | Ahora ya conocemos la organización de la zona de imagen y atributos y sabemos (del capítulo sobre rutinas de SAVE/LOAD) cargar en ella datos gráficos desde cinta o incluir los datos gráficos en nuestro propio programa y volcarlos con instrucciones |
* Efectos de fundido de los atributos de pantalla a negro. | * Efectos de fundido de los atributos de pantalla a negro. | ||
Línea 1078: | Línea 1080: | ||
Start: | Start: | ||
; Rellenamos la VRAM de pixeles copiando 6 KB de la ROM | ; Rellenamos la VRAM de pixeles copiando 6 KB de la ROM | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
; | ; | ||
Línea 1092: | Línea 1094: | ||
; | ; | ||
FadeScreen: | FadeScreen: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
fadegfx_loop1: | fadegfx_loop1: | ||
- | | + | |
- | | + | |
fadegfx_loop2: | fadegfx_loop2: | ||
- | | + | |
;-- Actuamos sobre el valor de los pixeles -- | ;-- Actuamos sobre el valor de los pixeles -- | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
fadegfx_mayor15: | fadegfx_mayor15: | ||
- | | + | |
- | | + | |
;-- Fin actuacion sobre el valor de los pixeles -- | ;-- Fin actuacion sobre el valor de los pixeles -- | ||
Línea 1130: | Línea 1132: | ||
fadegfx_save: | fadegfx_save: | ||
- | | + | |
- | | + | |
; Incrementamos el contador y comprobamos si hay que resetearlo | ; Incrementamos el contador y comprobamos si hay que resetearlo | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
fadegfx_continue: | fadegfx_continue: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | INCLUDE " | + | |
- | END 50000 | + | |
</ | </ | ||
Línea 1176: | Línea 1178: | ||
; | ; | ||
FadeAttributes: | FadeAttributes: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
fadescreen_loop1: | fadescreen_loop1: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
fadescreen_loop2: | fadescreen_loop2: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
fadescreen_ink_zero: | fadescreen_ink_zero: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
fadescreen_paper_zero: | fadescreen_paper_zero: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
Línea 1244: | Línea 1246: | ||
| | ||
+ | |||
+ | Del mismo modo, el libro **//40 Best Machine code Routines for the ZX Spectrum// | ||
+ | |||
+ | \\ | ||
+ | * Scrollear atributos a izquierda, derecha, arriba o abajo. | ||
+ | * Scroll de pantalla de un carácter (8 pixels) a izquierda, derecha, arriba o abajo. | ||
+ | * Scroll de pantalla de un pixel a izquierda, derecha, arriba o abajo. | ||
+ | * Mezclar dos imágenes con '' | ||
+ | * Inversión de la pantalla (píxeles a 0 se ponen a 1, y píxeles a 1 se ponen a 0). | ||
+ | * Invertir carácter vertical y horizontalmente. | ||
+ | * Rotar carácter 90º en sentido horario. | ||
+ | * Alterar todos los atributos de la pantalla (los bits deseados). | ||
+ | * Cambiar todos los atributos de la pantalla de un determinado valor por otro valor. | ||
+ | * Rellenado de regiones cerradas (poniendo a 1 los píxeles dentro de esas regiones). | ||
+ | * Impresión de figuras. | ||
+ | * Copia de una zona de la pantalla en otra, ampliándola por una cantidad entera (por ejemplo, x2 o x3). | ||
+ | |||
\\ | \\ | ||
===== La Shadow VRAM de los modelos de 128K ===== | ===== La Shadow VRAM de los modelos de 128K ===== | ||
- | En el capítulo dedicado a la paginación de memoria en los modelos de 128KB se habló de la paginación de bloques de 16KB sobre el área entre $C000 y $FFFF. El bloque de 16KB que almacena la videoram (el bloque 5, o, como se le conoce técnicamente, | + | En el capítulo dedicado a la paginación de memoria en los modelos de 128KB se habló de la paginación de bloques de 16KB sobre el área entre $c000 y $ffff. El bloque de 16KB que almacena la videoram (el bloque 5, o, como se le conoce técnicamente, |
\\ | \\ | ||
Línea 1257: | Línea 1276: | ||
\\ | \\ | ||
- | En los modelos de 128K, existe un segundo bloque de 16KB que podemos utilizar como VideoRAM (**Shadow VRAM**). El Z80 y la ULA nos permiten mapear **RAM7** sobre $C000-$FFFF, dejando la VideoRAM original sobre $4000. Más interesante todavía, la ULA puede visualizar el contenido de RAM7 en lugar del de RAM5 aunque no hayamos mapeado RAM7 en ningún sitio. Y recordemos que también podemos mapear la VRAM estándar (RAM5) sobre $C000, accediendo a ella a través de $C000 además de mediante $4000. | + | En los modelos de 128K, existe un segundo bloque de 16KB que podemos utilizar como VideoRAM (**Shadow VRAM**). El Z80 y la ULA nos permiten mapear **RAM7** sobre $c000-$ffff, dejando la VideoRAM original sobre $4000. Más interesante todavía, la ULA puede visualizar el contenido de RAM7 en lugar del de RAM5 aunque no hayamos mapeado RAM7 en ningún sitio. Y recordemos que también podemos mapear la VRAM estándar (RAM5) sobre $c000, accediendo a ella a través de $c000 además de mediante $4000. |
- | El poder visualizar una VRAM aunque no esté mapeada y el poder mapear tanto RAM5 como RAM7 sobre $C000 nos permite organizar el código de nuestro programa para que siempre escriba sobre $C000, teniendo mapeada en $C000 la pantalla que actualmente no esté visible. | + | El poder visualizar una VRAM aunque no esté mapeada y el poder mapear tanto RAM5 como RAM7 sobre $c000 nos permite organizar el código de nuestro programa para que siempre escriba sobre $c000, teniendo mapeada en $c000 la pantalla que actualmente no esté visible. |
La utilidad principal de esta funcionalidad es la de poder generar un cuadro de imagen o animación en una " | La utilidad principal de esta funcionalidad es la de poder generar un cuadro de imagen o animación en una " | ||
Línea 1266: | Línea 1285: | ||
\\ | \\ | ||
- | * Mapeamos RAM7 sobre $C000. | + | * Mapeamos RAM7 sobre $c000. |
* Visualizamos RAM5 (RAM7 no es visible). | * Visualizamos RAM5 (RAM7 no es visible). | ||
- | * Trabajamos sobre $C000 (sobre RAM7). Los cambios en nuestra pantalla shadow no son visibles. | + | * Trabajamos sobre $c000 (sobre RAM7). Los cambios en nuestra pantalla shadow no son visibles. |
- | * Esperamos una interrupción (mediante | + | * Esperamos una interrupción (mediante |
* Cambiamos la visualización a RAM7 (RAM5 deja de ser visible). | * Cambiamos la visualización a RAM7 (RAM5 deja de ser visible). | ||
- | * Mapeamos ahora RAM5 sobre $C000. | + | * Mapeamos ahora RAM5 sobre $c000. |
- | * Trabajamos sobre $C000 (sobre RAM5). Los cambios en nuestra pantalla shadow no son visibles. | + | * Trabajamos sobre $c000 (sobre RAM5). Los cambios en nuestra pantalla shadow no son visibles. |
* Repetimos el proceso. | * Repetimos el proceso. | ||
\\ | \\ | ||
- | Con este mecanismo siempre trabajamos sobre $C000 pero los cambios que realizamos sobre esta pantalla virtual no son perceptibles por el usuario. Cambiando la visualización de la VRAM a nuestra pantalla actual tras una interrupción hacemos los cambios visibles de forma inmediata, sin que el haz de electrones afecte a nuestro scroll o al dibujado de sprites. La tasa de fotogramas por segundo ya no sería de 50 (no podríamos generar 1 cuadro de imagen por interrupción) pero se evitaría un posible molesto efecto de parpadeo o cortinilla. | + | Con este mecanismo siempre trabajamos sobre $c000 pero los cambios que realizamos sobre esta pantalla virtual no son perceptibles por el usuario. Cambiando la visualización de la VRAM a nuestra pantalla actual tras una interrupción hacemos los cambios visibles de forma inmediata, sin que el haz de electrones afecte a nuestro scroll o al dibujado de sprites. La tasa de fotogramas por segundo ya no sería de 50 (no podríamos generar 1 cuadro de imagen por interrupción) pero se evitaría un posible molesto efecto de parpadeo o cortinilla. |
- | La desventaja de este sistema es que utilizamos $C000-$FFFF como pantalla virtual con lo que perdemos 16KB efectivos de RAM así como la posibilidad de paginar sobre $C000. Nos quedan así 16KB de memoria (entre $8000 y $BFFF) para alojar el código de nuestro programa, los datos gráficos, textos, etc. Esto puede ser una enorme limitación según el tipo de juego o programa que estemos realizando. | + | La desventaja de este sistema es que utilizamos $c000-$ffff como pantalla virtual con lo que perdemos 16KB efectivos de RAM así como la posibilidad de paginar sobre $c000. Nos quedan así 16KB de memoria (entre $8000 y $bfff) para alojar el código de nuestro programa, los datos gráficos, textos, etc. Esto puede ser una enorme limitación según el tipo de juego o programa que estemos realizando. |
- | En realidad, si diseñamos adecuadamente nuestro programa, podemos aprovechar más de 16KB, puesto que sólo necesitamos mapear RAM5 ó RAM7 en $C000 durante la generación de la pantalla virtual. Esto obliga a que los gráficos, fuentes, sprites y mapeados del juego deban estar disponibles en $8000-$BFFF, pero una vez finalizada la generación de la pantalla podemos volver a mapear RAM0 sobre $C000, volviendo a la lógica del juego que podría estar ubicada en ese bloque, junto al resto de variables, imágenes o textos usados en los menúes, efectos sonoros, músicas, etc. | + | En realidad, si diseñamos adecuadamente nuestro programa, podemos aprovechar más de 16KB, puesto que sólo necesitamos mapear RAM5 ó RAM7 en $c000 durante la generación de la pantalla virtual. Esto obliga a que los gráficos, fuentes, sprites y mapeados del juego deban estar disponibles en $8000-$bfff, pero una vez finalizada la generación de la pantalla podemos volver a mapear RAM0 sobre $c000, volviendo a la lógica del juego que podría estar ubicada en ese bloque, junto al resto de variables, imágenes o textos usados en los menúes, efectos sonoros, músicas, etc. |
- | Como véis, se necesita tener muy controlada la ubicación de las diferentes rutinas y variables y diseñar el juego para que mapee la página adecuada en cada momento y salte a una rutina concreta sólo cuando la rutina a la que hace referencia un CALL esté contenida en la página mapeada. | + | Como véis, se necesita tener muy controlada la ubicación de las diferentes rutinas y variables y diseñar el juego para que mapee la página adecuada en cada momento y salte a una rutina concreta sólo cuando la rutina a la que hace referencia un call esté contenida en la página mapeada. |
- | Se reseñó también, en el apartado // | + | Se reseñó también, en el apartado // |
\\ | \\ | ||
Línea 1293: | Línea 1312: | ||
\\ | \\ | ||
- | Como puede verse en la figura anterior, los modos Bit2 = 0, Bit1 = 1 (Bancos 4-5-6-3) y Bit2 = 1, Bit 1=1 (Bancos 4-7-6-3) del puerto $1FFD permiten paginar cualquiera de las 2 videorams (RAM5 o RAM7) sobre $4000. | + | Como puede verse en la figura anterior, los modos Bit2 = 0, Bit1 = 1 (Bancos 4-5-6-3) y Bit2 = 1, Bit 1=1 (Bancos 4-7-6-3) del puerto $1ffd permiten paginar cualquiera de las 2 videorams (RAM5 o RAM7) sobre $4000. |
- | Pese a las posibilidades de " | + | Pese a las posibilidades de " |
\\ | \\ |