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Última revisiónAmbos lados, revisión siguiente | ||
cursos:ensamblador:gfx1_vram [03-11-2010 07:01] – [La Shadow VRAM de los modelos de 128K] sromero | cursos:ensamblador:gfx1_vram [21-01-2024 18:11] – [Efectos sobre la imagen y los atributos] sromero | ||
---|---|---|---|
Línea 1: | Línea 1: | ||
- | |||
====== Gráficos (I): la videomemoria del Spectrum ====== | ====== Gráficos (I): la videomemoria del Spectrum ====== | ||
Línea 9: | Línea 8: | ||
Para comprender el funcionamiento de la videomemoria del Spectrum debemos empezar por comprender cómo el monitor o TV CRT genera las imágenes. | Para comprender el funcionamiento de la videomemoria del Spectrum debemos empezar por comprender cómo el monitor o TV CRT genera las imágenes. | ||
- | Los monitores/ | + | Los monitores/ |
| | ||
Línea 30: | Línea 29: | ||
La ULA tiene definidos los colores del Spectrum con unas componentes de color concretas que podemos ver aproximadamente en la siguiente tabla y en la imagen donde se representan: | La ULA tiene definidos los colores del Spectrum con unas componentes de color concretas que podemos ver aproximadamente en la siguiente tabla y en la imagen donde se representan: | ||
+ | |< 50% >| | ||
^ Valor ^ Color ^ Componentes RGB ^ | ^ Valor ^ Color ^ Componentes RGB ^ | ||
- | | 0 | Negro | (0, 0, 0 ) | | + | | 0 | Negro | (0, 0, 0 ) | |
- | | 1 | Azul | (0, 0, 192) | | + | | 1 | Azul | (0, 0, 192) | |
- | | 2 | Rojo | (192, 0, 0) | | + | | 2 | Rojo | (192, 0, 0) | |
- | | 3 | Magenta | (192, 0, 192) | | + | | 3 | Magenta | (192, 0, 192) | |
- | | 4 | Verde | (0, 192, 0) | | + | | 4 | Verde | (0, 192, 0) | |
- | | 5 | Cian | (0, 192, 192) | | + | | 5 | Cian | (0, 192, 192) | |
- | | 6 | Amarillo | (192, 192, 0) | | + | | 6 | Amarillo | (192, 192, 0) | |
- | | 7 | Blanco | (192, 192, 192) | | + | | 7 | Blanco | (192, 192, 192) | |
- | | 8 | Negro + Brillo | (0, 0, 0) | | + | | 8 | Negro + Brillo | (0, 0, 0) | |
- | | 9 | Azul + Brillo | (0, 0, 255) | | + | | 9 | Azul + Brillo | (0, 0, 255) | |
- | | 10 | Rojo + Brillo | (255, 0, 0) | | + | | 10 | Rojo + Brillo | (255, 0, 0) | |
- | | 11 | Magenta + Brillo | (255, 0, 255) | | + | | 11 | Magenta + Brillo | (255, 0, 255) | |
- | | 12 | Verde + Brillo | (0, 255, 0) | | + | | 12 | Verde + Brillo | (0, 255, 0) | |
- | | 13 | Cian + Brillo | (0, 255, 255) | | + | | 13 | Cian + Brillo | (0, 255, 255) | |
- | | 14 | Amarillo + Brillo | (255, 255, 0) | | + | | 14 | Amarillo + Brillo | (255, 255, 0) | |
| 15 | Blanco + Brillo | (255, 255, 255) | | | 15 | Blanco + Brillo | (255, 255, 255) | | ||
\\ | \\ | ||
- | {{ cursos: | + | {{ cursos: |
;#; | ;#; | ||
//La gama de colores del Spectrum// | //La gama de colores del Spectrum// | ||
Línea 59: | Línea 59: | ||
Como ya vimos en el capítulo dedicado a las interrupciones, | Como ya vimos en el capítulo dedicado a las interrupciones, | ||
- | El haz de electrones traza pues, scanline a scanline, toda la pantalla hasta llegar a la parte inferior derecha, momento en el que el haz de electrones vuelve a la parte superior izquierda dejando de bombardear electrones durante el retorno, sincronizándose con el dispositivo al que esté conectado (la ULA y el modulador de vídeo del Spectrum en este caso) mediante una señal VSYNC. | + | El haz de electrones traza pues, scanline a scanline, toda la pantalla hasta llegar a la parte inferior derecha, momento en el que el haz de electrones vuelve a la parte superior izquierda dejando de bombardear electrones durante el retorno, sincronizándose con el dispositivo al que esté conectado (la ULA y el modulador de vídeo del Spectrum en este caso) mediante una señal VSYNC. |
\\ | \\ | ||
Línea 65: | Línea 65: | ||
;#; | ;#; | ||
//Proceso de retrazado de la imagen// | //Proceso de retrazado de la imagen// | ||
- | ;#;\\ | + | ;#; |
+ | \\ | ||
Este proceso se repite continuamente (a razón de 50 ó 60 veces por segundo según el sistema de televisión de nuestra región) y no se puede interrumpir ni variar (ni el tiempo de avance de la señal de televisión en horizontal ni el tiempo total que se tarda en retrazar un cuadro. | Este proceso se repite continuamente (a razón de 50 ó 60 veces por segundo según el sistema de televisión de nuestra región) y no se puede interrumpir ni variar (ni el tiempo de avance de la señal de televisión en horizontal ni el tiempo total que se tarda en retrazar un cuadro. | ||
Línea 78: | 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 86: | Línea 87: | ||
;#; | ;#; | ||
//La videoram en el mapa de memoria del Spectrum// | //La videoram en el mapa de memoria del Spectrum// | ||
- | ;#;\\ | + | ;#; |
+ | \\ | ||
Las rutinas de la ROM o de BASIC que dibujan puntos, líneas, rectángulos o caracteres de texto, lo que realmente hacen internamente es escribir datos en posiciones concretas y calculadas de la videoram ya que estos datos escritos se convertirán en píxeles en el monitor cuando la ULA los recoja en su proceso de envío de datos al monitor y éste los dibuje en la pantalla. | Las rutinas de la ROM o de BASIC que dibujan puntos, líneas, rectángulos o caracteres de texto, lo que realmente hacen internamente es escribir datos en posiciones concretas y calculadas de la videoram ya que estos datos escritos se convertirán en píxeles en el monitor cuando la ULA los recoja en su proceso de envío de datos al monitor y éste los dibuje en la pantalla. | ||
Línea 129: | Línea 131: | ||
; Ejemplo de escritura de un grafico con forma de A | ; Ejemplo de escritura de un grafico con forma de A | ||
- | | + | |
- | LD HL, 18514 | + | ld hl, 18514 |
- | LD A, 60 | + | ld a, 60 |
- | | + | |
- | LD HL, 18770 | + | ld hl, 18770 |
- | LD A, 66 | + | ld a, 66 |
- | | + | |
- | LD HL, 19026 | + | ld hl, 19026 |
- | LD A, 66 | + | ld a, 66 |
- | | + | |
- | LD HL, 19282 | + | ld hl, 19282 |
- | LD A, 126 ; 01111110b | + | ld a, 126 ; 01111110b |
- | | + | |
- | LD HL, 19538 | + | ld hl, 19538 |
- | LD A, 66 | + | ld a, 66 |
- | | + | |
- | LD HL, 19794 | + | ld hl, 19794 |
- | LD A, 66 | + | ld a, 66 |
- | | + | |
- | LD HL, 20050 | + | ld hl, 20050 |
- | LD A, 66 ; 01000001b | + | ld a, %01000001 |
- | | + | |
- | LD HL, 20306 | + | ld hl, 20306 |
- | LD A, 0 ; 00000000b | + | ld a, 0 ; 00000000b |
- | | + | |
- | RET | + | ret |
- | END 50000 | + | |
+ | | ||
</ | </ | ||
Línea 170: | Línea 173: | ||
\\ | \\ | ||
- | {{ cursos: | + | {{ cursos: |
\\ | \\ | ||
Línea 188: | 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 198: | Línea 201: | ||
En la siguiente imagen podemos ver un ejemplo simplificado de cómo se produce la generación de la imagen como " | En la siguiente imagen podemos ver un ejemplo simplificado de cómo se produce la generación de la imagen como " | ||
- | |||
\\ | \\ | ||
Línea 223: | 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 231: | Línea 233: | ||
\\ | \\ | ||
- | {{ cursos: | + | {{ cursos: |
\\ | \\ | ||
- | A continuación pulsamos una tecla y se ejecuta el "INK 2 + PLOT + DRAW" | + | A continuación pulsamos una tecla y se ejecuta el '' |
\\ | \\ | ||
- | {{ cursos: | + | {{ cursos: |
\\ | \\ | ||
Línea 243: | Línea 245: | ||
\\ | \\ | ||
- | {{ cursos: | + | {{ cursos: |
\\ | \\ | ||
Línea 249: | Línea 251: | ||
\\ | \\ | ||
- | {{ cursos: | + | {{ cursos: |
;#; | ;#; | ||
//" | //" | ||
Línea 258: | Línea 260: | ||
\\ | \\ | ||
- | {{ cursos: | + | {{ cursos: |
;#; | ;#; | ||
//Area de juego monocolor en H.A.T.E.// | //Area de juego monocolor en H.A.T.E.// | ||
Línea 269: | Línea 271: | ||
\\ | \\ | ||
- | {{ cursos: | + | {{ cursos: |
;#; | ;#; | ||
//Excelente diseño gráfico que disimula la colisión de atributos// | //Excelente diseño gráfico que disimula la colisión de atributos// | ||
Línea 278: | Línea 280: | ||
A continuación veremos una descripción más detallada de cada una de estas 2 áreas de memoria. | A continuación veremos una descripción más detallada de cada una de estas 2 áreas de memoria. | ||
- | |||
\\ | \\ | ||
===== 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 291: | Línea 292: | ||
| | ||
+ | |< 60% >| | ||
^ Bits de (16384) ^ 7 ^ 6 ^ 5 ^ 4 ^ 3 ^ 2 ^ 1 ^ 0 ^ | ^ Bits de (16384) ^ 7 ^ 6 ^ 5 ^ 4 ^ 3 ^ 2 ^ 1 ^ 0 ^ | ||
| Pixel | (0,0) | (1,0) | (2,0) | (3,0) | (4,0) | (5,0) | (6,0) | (7,0) | | | Pixel | (0,0) | (1,0) | (2,0) | (3,0) | (4,0) | (5,0) | (6,0) | (7,0) | | ||
Línea 312: | Línea 314: | ||
Si avanzamos a la siguiente celdilla de memoria, la $4001 (o 16385), tendremos el estado de los siguientes píxeles de la misma línea horizontal: | Si avanzamos a la siguiente celdilla de memoria, la $4001 (o 16385), tendremos el estado de los siguientes píxeles de la misma línea horizontal: | ||
+ | |< 60% >| | ||
^ Bit de (16385) ^ 7 ^ 6 ^ 5 ^ 4 ^ 3 ^ 2 ^ 1 ^ 0 ^ | ^ Bit de (16385) ^ 7 ^ 6 ^ 5 ^ 4 ^ 3 ^ 2 ^ 1 ^ 0 ^ | ||
| Pixel | (8,0) | (9,0) | (10,0) | (11,0) | (12,0) | (13,0) | (14,0) | (15,0) | | | Pixel | (8,0) | (9,0) | (10,0) | (11,0) | (12,0) | (13,0) | (14,0) | (15,0) | | ||
Línea 317: | Línea 320: | ||
De nuevo, avanzando 1 byte más en memoria, avanzamos otros 8 píxeles horizontalmente: | De nuevo, avanzando 1 byte más en memoria, avanzamos otros 8 píxeles horizontalmente: | ||
+ | |< 60% >| | ||
^ Bit de (16386) ^ 7 ^ 6 ^ 5 ^ 4 ^ 3 ^ 2 ^ 1 ^ 0 ^ | ^ Bit de (16386) ^ 7 ^ 6 ^ 5 ^ 4 ^ 3 ^ 2 ^ 1 ^ 0 ^ | ||
| Pixel | (16,0) | (17,0) | (18,0) | (19,0) | (20,0) | (21,0) | (22,0) | (23,0) | | | Pixel | (16,0) | (17,0) | (18,0) | (19,0) | (20,0) | (21,0) | (22,0) | (23,0) | | ||
Línea 322: | Línea 326: | ||
Así, hasta que llegamos al byte número 32 desde 16384, es decir, a la celdilla 16415, donde: | Así, hasta que llegamos al byte número 32 desde 16384, es decir, a la celdilla 16415, donde: | ||
+ | |< 60% >| | ||
^ Bit de (16415) ^ 7 ^ 6 ^ 5 ^ 4 ^ 3 ^ 2 ^ 1 ^ 0 ^ | ^ Bit de (16415) ^ 7 ^ 6 ^ 5 ^ 4 ^ 3 ^ 2 ^ 1 ^ 0 ^ | ||
| Pixel | (248,0) | (249,0) | (250,0) | (251,0) | (252,0) | (253,0) | (254,0) | (255,0) | | | Pixel | (248,0) | (249,0) | (250,0) | (251,0) | (252,0) | (253,0) | (254,0) | (255,0) | | ||
Línea 329: | 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 336: | Línea 341: | ||
\\ | \\ | ||
- | {{ cursos: | + | {{ cursos: |
\\ | \\ | ||
Línea 343: | Línea 348: | ||
Por desgracia, esto no es así, y los 32 bytes a partir de 16416 no hacen referencia a la segunda línea de pantalla sino a la primera línea del segundo " | Por desgracia, esto no es así, y los 32 bytes a partir de 16416 no hacen referencia a la segunda línea de pantalla sino a la primera línea del segundo " | ||
+ | |< 60% >| | ||
^ Bit de (16416) ^ 7 ^ 6 ^ 5 ^ 4 ^ 3 ^ 2 ^ 1 ^ 0 ^ | ^ Bit de (16416) ^ 7 ^ 6 ^ 5 ^ 4 ^ 3 ^ 2 ^ 1 ^ 0 ^ | ||
| Pixel | (0,8) | (1,8) | (2,8) | (3,8) | (4,8) | (5,8) | (6,8) | (7,8) | | | Pixel | (0,8) | (1,8) | (2,8) | (3,8) | (4,8) | (5,8) | (6,8) | (7,8) | | ||
Línea 350: | 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 | ||
</ | </ | ||
\\ | \\ | ||
- | {{ cursos: | + | {{ cursos: |
\\ | \\ | ||
Línea 381: | 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 390: | 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). |
\\ | \\ | ||
- | + | ||
Y, resumiendo en un sólo párrafo la organización de cada tercio: | Y, resumiendo en un sólo párrafo la organización de cada tercio: | ||
Línea 413: | Línea 419: | ||
Con el programa de ejemplo del apartado // | Con el programa de ejemplo del apartado // | ||
- | | + | |
<code z80> | <code z80> | ||
Línea 421: | Línea 427: | ||
; | ; | ||
ClearScreen: | ClearScreen: | ||
- | PUSH HL | + | push hl |
- | PUSH DE | + | push de |
- | + | push bc | |
- | LD HL, 16384 ; HL = Inicio de la videoram | + | |
- | | + | ld hl, 16384 ; HL = Inicio de la videoram |
- | LD DE, 16385 ; Apuntamos DE a 16385 | + | |
- | LD BC, 192*32-1 | + | ld de, 16385 ; Apuntamos DE a 16385 |
- | | + | ld bc, 192*32-1 |
- | ; porque ya hemos escrito en 16384. | + | |
- | POP DE | + | ; porque ya hemos escrito en 16384. |
- | POP HL | + | |
- | | + | pop bc |
+ | pop de | ||
+ | pop hl | ||
+ | ret | ||
</ | </ | ||
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 '' | ||
+ | |||
\\ | \\ | ||
==== Explorando el área de imagen con un ejemplo ==== | ==== Explorando el área de imagen con un ejemplo ==== | ||
- | | + | |
Este programa carga HL con el inicio del área de imágen de la videomemoria (16384 o $4000), y escribe bloques de 32 bytes (todo un scanline horizontal) con el valor 255 (11111111b o, lo que es lo mismo, los 8 píxeles de ese bloque activos). | Este programa carga HL con el inicio del área de imágen de la videomemoria (16384 o $4000), y escribe bloques de 32 bytes (todo un scanline horizontal) con el valor 255 (11111111b o, lo que es lo mismo, los 8 píxeles de ese bloque activos). | ||
Línea 455: | Línea 467: | ||
; Mostrando la organizacion de la videomemoria | ; Mostrando la organizacion de la videomemoria | ||
- | | + | |
; Pseudocodigo del programa: | ; Pseudocodigo del programa: | ||
- | ; | + | ; |
; Limpiamos la pantalla | ; Limpiamos la pantalla | ||
; Apuntamos HL a 16384 | ; Apuntamos HL a 16384 | ||
Línea 468: | Línea 480: | ||
Start: | Start: | ||
- | LD A, 0 | + | ld a, 0 |
- | | + | |
- | LD HL, 16384 ; HL apunta a la VRAM | + | ld hl, 16384 ; HL apunta a la VRAM |
- | LD B, 192 ; Repetimos para 192 lineas | + | ld b, 192 ; Repetimos para 192 lineas |
bucle_192_lineas: | bucle_192_lineas: | ||
- | LD D, B ; Nos guardamos el valor de D para el | + | ld d, b ; Nos guardamos el valor de D para el |
- | | + | |
- | LD B, 32 ; B=32 para el bucle interior | + | ld b, 32 ; B=32 para el bucle interior |
- | ; Esperamos que se pulse y libere tecla | + | call Wait_For_Key |
- | CALL Wait_For_Keys_Pressed | + | |
- | CALL Wait_For_Keys_Released | + | |
- | LD A, 255 ; 255 = 11111111b = todos los pixeles | + | ld a, 255 ; 255 = 11111111b = todos los pixeles |
bucle_32_bytes: | bucle_32_bytes: | ||
- | LD (HL), A ; Almacenamos A en (HL) = 8 pixeles | + | ld (hl), a ; Almacenamos A en (HL) = 8 pixeles |
- | INC HL ; siguiente byte (siguientes 8 pix.) | + | inc hl ; siguiente byte (siguientes 8 pix.) |
- | | + | |
- | LD B, D ; Recuperamos el B del bucle exterior | + | ld b, d ; Recuperamos el B del bucle exterior |
- | + | ||
- | DJNZ bucle_192_lineas | + | |
- | + | ||
- | JP Start ; Inicio del programa | + | |
- | | + | |
- | ;----------------------------------------------------------------------- | + | djnz bucle_192_lineas |
- | ; Esta rutina espera a que haya alguna tecla pulsada para volver. | + | |
- | ;----------------------------------------------------------------------- | + | jp Start ; Inicio del programa |
- | Wait_For_Keys_Pressed: | + | |
- | XOR A | + | |
- | IN A, (254) | + | |
- | OR 224 | + | |
- | INC A | + | |
- | JR Z, Wait_For_Keys_Pressed | + | |
- | RET | + | |
- | + | ||
- | ; | + | |
- | ; Esta rutina espera a que no haya ninguna tecla pulsada para volver. | + | |
- | ; | + | |
- | Wait_For_Keys_Released: | + | |
- | XOR A | + | |
- | IN A, (254) | + | |
- | OR 224 | + | |
- | INC A | + | |
- | JR NZ, Wait_For_Keys_Released | + | |
- | RET | + | |
; | ; | ||
Línea 524: | Línea 511: | ||
; | ; | ||
ClearScreen: | ClearScreen: | ||
- | LD HL, 16384 | + | ld hl, 16384 |
- | | + | |
- | LD DE, 16385 | + | ld de, 16385 |
- | LD BC, 192*32-1 | + | ld bc, 192*32-1 |
- | LDIR | + | ldir |
- | RET | + | ret |
+ | |||
+ | INCLUDE " | ||
- | END 50000 | + | |
</ | </ | ||
Línea 537: | Línea 526: | ||
\\ | \\ | ||
- | {{ cursos: | + | {{ cursos: |
| | ||
Línea 544: | Línea 533: | ||
\\ | \\ | ||
- | {{ cursos: | + | {{ cursos: |
| | ||
- | 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 566: | Línea 555: | ||
Esta organización de memoria tiene como objetivo el facilitar las rutinas de impresión de texto, algo que podemos ver en las posiciones de inicio de las diferentes líneas de un mismo carácter: | Esta organización de memoria tiene como objetivo el facilitar las rutinas de impresión de texto, algo que podemos ver en las posiciones de inicio de las diferentes líneas de un mismo carácter: | ||
+ | |< 50% >| | ||
^ Scanline del carácter ^ Dirección de memoria ^ | ^ Scanline del carácter ^ Dirección de memoria ^ | ||
| 0 | $4000 | | | 0 | $4000 | | ||
Línea 576: | 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 584: | 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. | ||
- | | + | |
La organización lógica del área de atributos es más sencilla y directa que la del área de imagen. Aquí, los 32 primeros bytes del área de atributos se corresponden con los 32 primeros bloques horizontales de la pantalla. Es decir, la celdilla 22528 se corresponde con el bloque (0,0), la 22529 se corresponde con (1,0), la 22530 con (2,0), y así hasta llegar a la celdilla 22559 en (31,0). La siguiente celdilla en memoria, 22560, se corresponde con el siguiente bloque en pantalla, el primero de la segunda línea, (0,1), y así de forma sucesiva. | La organización lógica del área de atributos es más sencilla y directa que la del área de imagen. Aquí, los 32 primeros bytes del área de atributos se corresponden con los 32 primeros bloques horizontales de la pantalla. Es decir, la celdilla 22528 se corresponde con el bloque (0,0), la 22529 se corresponde con (1,0), la 22530 con (2,0), y así hasta llegar a la celdilla 22559 en (31,0). La siguiente celdilla en memoria, 22560, se corresponde con el siguiente bloque en pantalla, el primero de la segunda línea, (0,1), y así de forma sucesiva. | ||
Línea 599: | 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: | ||
+ | |< 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: | ||
< | < | ||
- | | + | |
- | </ | + | </ |
O, con desplazamientos: | O, con desplazamientos: | ||
< | < | ||
- | | + | |
- | </ | + | </ |
Si en vez de una posición de bloque tenemos una posición de pixel, podemos convertirla primero a bloque dividiendo por 8: | Si en vez de una posición de bloque tenemos una posición de pixel, podemos convertirla primero a bloque dividiendo por 8: | ||
Línea 645: | Línea 636: | ||
< | < | ||
| | ||
- | </ | + | </ |
Con desplazamientos: | Con desplazamientos: | ||
Línea 651: | Línea 642: | ||
< | < | ||
| | ||
- | </ | + | </ |
La información en cada byte de este área se codifica de la siguiente manera: | La información en cada byte de este área se codifica de la siguiente manera: | ||
\\ | \\ | ||
+ | |< 40% >| | ||
^ Bit ^ 7 ^ 6 ^ 5 - 4 - 3 ^ 2 - 1 - 0 ^ | ^ Bit ^ 7 ^ 6 ^ 5 - 4 - 3 ^ 2 - 1 - 0 ^ | ||
| Valor | FLASH | BRIGHT | | Valor | FLASH | BRIGHT | ||
Línea 669: | Línea 661: | ||
| | ||
+ | |< 30% >| | ||
^ Valor ^ Color ^ | ^ Valor ^ Color ^ | ||
| 0 | Negro | | | 0 | Negro | | ||
Línea 681: | Línea 674: | ||
A estos colores se les puede activar el bit de brillo para obtener una tonalidad más cercana a la intensidad máxima de dicho color. Examinando de nuevo la captura que veíamos al principio del artículo: | A estos colores se les puede activar el bit de brillo para obtener una tonalidad más cercana a la intensidad máxima de dicho color. Examinando de nuevo la captura que veíamos al principio del artículo: | ||
- | {{ cursos: | + | {{ cursos: |
- | Si tuvieramos que codificar mediante una operación matemática un color directamente como atributo, y sabiendo que las multiplicaciones por potencias de dos equivalen a desplazamientos, | + | La relación de los colores con su " |
+ | |||
+ | |< 60% >| | ||
+ | ^ Valor ^ Bits " | ||
+ | | 0 | 0000b | Negro | (0, 0, 0 ) | | ||
+ | | 1 | 0001b | Azul | (0, 0, 192) | | ||
+ | | 2 | 0010b | Rojo | (192, 0, 0) | | ||
+ | | 3 | 0011b | Magenta | (192, 0, 192) | | ||
+ | | 4 | 0100b | Verde | (0, 192, 0) | | ||
+ | | 5 | 0101b | Cian | (0, 192, 192) | | ||
+ | | 6 | 0110b | Amarillo | (192, 192, 0) | | ||
+ | | 7 | 0111b | Blanco | (192, 192, 192) | | ||
+ | | 8 | 1000b | Negro + Brillo | (0, 0, 0) | | ||
+ | | 9 | 1001b | Azul + Brillo | (0, 0, 255) | | ||
+ | | 10 | 1010b | Rojo + Brillo | (255, 0, 0) | | ||
+ | | 11 | 1011b | Magenta + Brillo | (255, 0, 255) | | ||
+ | | 12 | 1100b | Verde + Brillo | (0, 255, 0) | | ||
+ | | 13 | 1101b | Cian + Brillo | (0, 255, 255) | | ||
+ | | 14 | 1110b | Amarillo + Brillo | (255, 255, 0) | | ||
+ | | 15 | 1111b | Blanco + Brillo | (255, 255, 255) | | ||
+ | |||
+ | Todos los colores se componen a través del estado de las componentes R, G y B (entre 0 y 1), así como de mezclas de dichas componentes (Ej: Cian = 5 = 101b = R+B). Sería perfectamente posible separar la memoria de atributos en 3 pantallas alojando el estado de las 3 componentes de color (o incluso de combinaciones de ellas) extrayendo la información de los bits correspondientes. | ||
+ | |||
+ | Pero volvamos a cada atributo individual: | ||
< | < | ||
Línea 706: | Línea 722: | ||
<code z80> | <code z80> | ||
- | | + | ; Mostrando la organizacion de la videomemoria (atributos) |
- | + | ORG 50000 | |
- | | + | |
; Pseudocodigo del programa: | ; Pseudocodigo del programa: | ||
- | ; | + | ; |
; Borramos la pantalla | ; Borramos la pantalla | ||
; Apuntamos HL a 22528 | ; Apuntamos HL a 22528 | ||
Línea 721: | Línea 736: | ||
Start: | Start: | ||
- | LD A, 0 | + | ld a, 0 |
- | | + | |
- | LD HL, 22528 ; HL apunta a la VRAM | + | ld hl, 22528 ; HL apunta a la VRAM |
- | LD B, 24 ; Repetimos para 192 lineas | + | ld b, 24 |
bucle_lineas: | bucle_lineas: | ||
- | LD D, B ; Nos guardamos el valor de D para el | + | ld d, b ; Nos guardamos el valor de D para el |
- | | + | |
- | LD B, 32 ; B=32 para el bucle interior | + | ld b, 32 ; B=32 para el bucle interior |
- | ; Esperamos que se pulse y libere tecla | + | call Wait_For_Key |
- | CALL Wait_For_Keys_Pressed | + | |
- | CALL Wait_For_Keys_Released | + | |
- | LD A, (papel) | + | ld a, (papel) |
- | INC A ; Lo incrementamos | + | inc a ; Lo incrementamos |
- | | + | |
- | | + | |
- | JR NZ, | + | jr nz, |
- | LD A, 255 | + | ld a, 255 |
- | | + | |
- | XOR A ; A=0 | + | xor a ; A=0 |
no_resetear_papel: | no_resetear_papel: | ||
- | SLA A ; Desplazamos A 3 veces a la izquierda | + | sla a ; Desplazamos A 3 veces a la izquierda |
- | SLA A ; para colocar el valor 0-7 en los bits | + | sla a ; para colocar el valor 0-7 en los bits |
- | SLA A ; donde se debe ubicar PAPER (bits 3-5). | + | sla a ; donde se debe ubicar PAPER (bits 3-5). |
bucle_32_bytes: | bucle_32_bytes: | ||
- | LD (HL), A ; Almacenamos A en (HL) = attrib de 8x8 | + | ld (hl), a ; Almacenamos A en (HL) = attrib de 8x8 |
- | INC HL ; siguiente byte (siguientes 8x8 pixeles.) | + | inc hl ; siguiente byte (siguientes 8x8 pixeles.) |
- | | + | |
- | LD B, D ; Recuperamos el B del bucle exterior | + | ld b, d ; Recuperamos el B del bucle exterior |
- | + | ||
- | DJNZ bucle_lineas | + | |
- | JP Start ; Inicio del programa | + | djnz bucle_lineas |
- | papel defb | + | jp Start ; Inicio |
- | + | ||
- | + | ||
- | ; | + | |
- | ; Esta rutina espera a que haya alguna tecla pulsada para volver. | + | |
- | ; | + | |
- | Wait_For_Keys_Pressed: | + | |
- | XOR A | + | |
- | IN A, (254) | + | |
- | OR 224 | + | |
- | INC A | + | |
- | JR Z, Wait_For_Keys_Pressed | + | |
- | RET | + | |
- | + | ||
- | + | ||
- | ; | + | |
- | ; Esta rutina espera a que no haya ninguna tecla pulsada para volver. | + | |
- | ; | + | |
- | Wait_For_Keys_Released: | + | |
- | XOR A | + | |
- | IN A, (254) | + | |
- | OR 224 | + | |
- | INC A | + | |
- | JR NZ, Wait_For_Keys_Released | + | |
- | RET | + | |
+ | papel DEFB | ||
; | ; | ||
Línea 795: | Línea 783: | ||
; | ; | ||
ClearScreen: | ClearScreen: | ||
- | LD HL, 16384 | + | ld hl, 16384 |
- | | + | |
- | LD DE, 16385 | + | ld de, 16385 |
- | LD BC, 192*32-1 | + | ld bc, 192*32-1 |
- | LDIR | + | ldir |
- | RET | + | ret |
- | END 50000 | + | INCLUDE " |
+ | |||
+ | | ||
</ | </ | ||
Línea 808: | Línea 798: | ||
\\ | \\ | ||
- | {{ cursos: | + | {{ cursos: |
\\ | \\ | ||
Línea 816: | 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 827: | Línea 816: | ||
; | ; | ||
ClearAttributes: | ClearAttributes: | ||
- | PUSH HL | + | push hl |
- | PUSH DE | + | push de |
- | + | push bc | |
- | LD HL, 22528 ; HL = Inicio del area de atributos | + | |
- | | + | ld hl, 22528 ; HL = Inicio del area de atributos |
- | LD DE, 22529 ; Apuntamos DE a 22528 | + | |
- | LD BC, 24*32-1 | + | ld de, 22529 ; Apuntamos DE a 22528 |
- | | + | ld bc, 24*32-1 |
- | ; porque ya hemos escrito en 22528. | + | |
- | | + | ; porque ya hemos escrito en 22528. |
- | | + | pop bc |
- | | + | pop de |
+ | pop hl | ||
+ | ret | ||
+ | </ | ||
+ | |||
+ | Dado lo habitual que puede ser llamar a '' | ||
+ | |||
+ | <code z80> | ||
+ | ; | ||
+ | ; Limpiar la pantalla con el patron de pixeles y atributos indicado. | ||
+ | ; Entrada: | ||
+ | ; | ||
+ | ClearScreenAttrib: | ||
+ | push de | ||
+ | push bc | ||
+ | push bc | ||
+ | |||
+ | ld a, h ; A = el atributo | ||
+ | ex af, af ; Nos guardamos el atributo en A' | ||
+ | ld a, l ; Cargamos en A el patron | ||
+ | ld hl, 16384 ; HL = Inicio del area de imagen | ||
+ | ld (hl), a ; Escribimos el valor de A en (HL) | ||
+ | ld de, 16385 ; Apuntamos | ||
+ | ld bc, 192*32-1 | ||
+ | | ||
+ | |||
+ | ex af, af ; Recuperamos A (atributo) de A' | ||
+ | inc hl ; Incrementamos HL y DE | ||
+ | inc de ; para entrar en area de atributos | ||
+ | ld (hl), a ; Almacenamos el atributo | ||
+ | ld bc, 24*32-1 | ||
+ | ldir | ||
+ | |||
+ | pop bc | ||
+ | pop bc | ||
+ | pop de | ||
+ | ret | ||
</ | </ | ||
Línea 847: | Línea 872: | ||
El área gráfica de 256x192 píxeles está centrada en el centro de la pantalla o monitor, dejando alrededor de ella un marco denominado BORDE. Este borde tiene 64 píxeles en las franjas horizontales y 48 píxeles en las verticales. | El área gráfica de 256x192 píxeles está centrada en el centro de la pantalla o monitor, dejando alrededor de ella un marco denominado BORDE. Este borde tiene 64 píxeles en las franjas horizontales y 48 píxeles en las verticales. | ||
- | 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 | ||
- | | + | |
- | + | ||
- | LD B, 6 ; 6 iteraciones, | + | ld b, 6 ; 6 iteraciones, |
start: | start: | ||
- | + | ||
bucle: | bucle: | ||
- | LD A, $7F ; Semifila B a ESPACIO | + | ld a, $7f ; Semifila B a ESPACIO |
- | IN A, ($FE) ; Leemos el puerto | + | in a, ($fe) ; Leemos el puerto |
- | | + | |
- | JR NZ, bucle ; Si esta a 1 (no pulsado), esperar | + | jr nz, bucle ; Si esta a 1 (no pulsado), esperar |
- | + | ||
- | LD A, B ; A = B | + | ld a, b ; A = B |
- | | + | |
- | + | ||
- | suelta_tecla: | + | suelta_tecla: |
- | LD A, $7F ; Semifila B a ESPACIO | + | ld a, $7f ; Semifila B a ESPACIO |
- | IN A, ($FE) ; Leemos el puerto | + | in a, ($fe) ; Leemos el puerto |
- | | + | |
- | JR Z, suelta_tecla | + | jr z, suelta_tecla |
- | + | ||
- | | + | |
- | LD B, 7 | + | ld b, 7 |
- | | + | |
- | + | ||
salir: | salir: | ||
- | RET | + | ret |
- | + | ||
; | ; | ||
; SetBorder: Cambio del color del borde al del registro A | ; SetBorder: Cambio del color del borde al del registro A | ||
; | ; | ||
SetBorder: | SetBorder: | ||
- | OUT (254), A | + | out ($fe), a |
- | RET | + | ret |
- | | + | |
</ | </ | ||
Línea 898: | Línea 923: | ||
\\ | \\ | ||
- | {{ cursos: | + | {{ cursos: |
+ | \\ | ||
- | + | Si por algún motivo necesitaramos actualizar la variable del sistema | |
- | 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: | + | |
<code z80> | <code z80> | ||
Línea 909: | Línea 934: | ||
; | ; | ||
SetBorder: | SetBorder: | ||
- | OUT (254), A ; Cambiamos el color del borde | + | out ($fe), a ; Cambiamos el color del borde |
- | RLCA | + | rlca |
- | RLCA | + | rlca |
- | | + | |
- | | + | |
- | JR NZ, SetBorder_fin | + | jr nz, SetBorder_fin |
- | | + | |
- | XOR 7 | + | xor %00000111 |
- | + | ||
SetBorder_fin: | SetBorder_fin: | ||
- | LD (23624), | + | ld (23624), |
- | + | ||
- | RET | + | ret |
</ | </ | ||
- | | + | |
| | ||
Línea 930: | 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 | ||
- | | + | |
- | + | ||
- | LD B, 6 ; 6 iteraciones, | + | ld b, 6 ; 6 iteraciones, |
start: | start: | ||
- | + | ||
bucle: | bucle: | ||
- | LD A, B ; A = B | + | ld a, b ; A = B |
- | | + | |
- | + | ||
- | | + | |
- | LD B, 7 | + | ld b, 7 |
- | | + | |
- | + | ||
salir: | salir: | ||
- | RET | + | ret |
+ | |||
+ | END 50000 | ||
</ | </ | ||
Línea 951: | Línea 978: | ||
\\ | \\ | ||
- | {{ cursos: | + | {{ cursos: |
\\ | \\ | ||
Línea 957: | 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 963: | Línea 990: | ||
\\ | \\ | ||
- | {{ cursos: | + | {{ cursos: |
\\ | \\ | ||
- | 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 23695), la cual almacena el atributo actual 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 |
- | + | ORG 50000 | |
- | | + | |
- | + | ||
- | ; Pseudocodigo del programa: | + | |
- | ; | + | |
- | ; Borramos la pantalla | + | |
- | ; Apuntamos HL a 22528 | + | |
- | ; Repetimos 24 veces: | + | |
- | ; Esperamos pulsacion de una tecla | + | |
- | ; Repetimos 32 veces: | + | |
- | ; | + | |
- | ; | + | |
Start: | Start: | ||
- | LD A, 1 ; Borde azul | + | ld a, 1 ; Borde azul |
- | CALL SetBorder | + | call BORDER |
- | LD A, 0 | + | |
- | CALL ClearScreen | + | |
- | LD A, 8+4 ; Atributos: rojo sobre azul | + | |
- | CALL ClearAttributes | + | |
- | LD HL, linea1 | + | ld a, 8+4 |
- | CALL PrintString | + | ld (CLS_COLOR), |
+ | call CLS | ||
- | LD A, 12 ; Atributos: verde sobre azul | + | ld a, 56 ; Negro sobre gris |
- | | + | |
- | LD HL, linea2 | + | ld de, linea1 |
- | | + | |
- | LD A, 64+2+9 | + | ld a, 12 ; Verde sobre azul |
- | | + | |
- | LD HL, linea2 | + | ld de, linea2 |
- | | + | |
- | | + | ld a, 64+2+9 |
- | CALL Wait_For_Keys_Pressed | + | ld (ATTR_T), a ; Cambiamos ATTR-T |
- | CALL Wait_For_Keys_Released | + | |
- | RET ; Fin del programa | + | ld de, linea2 |
+ | call PrintString | ||
- | ;----------------------------------------------------------------------- | + | call Wait_For_Key |
- | ; Esta rutina espera a que haya alguna | + | |
- | ; | + | |
- | Wait_For_Keys_Pressed: | + | |
- | XOR A | + | |
- | IN A, (254) | + | |
- | OR 224 | + | |
- | INC A | + | |
- | JR Z, Wait_For_Keys_Pressed | + | |
- | RET | + | |
- | ;----------------------------------------------------------------------- | + | ret |
- | ; Esta rutina espera a que no haya ninguna tecla pulsada para volver. | + | |
- | ; | + | |
- | Wait_For_Keys_Released: | + | |
- | XOR A | + | |
- | IN A, (254) | + | |
- | OR 224 | + | |
- | INC A | + | |
- | JR NZ, Wait_For_Keys_Released | + | |
- | RET | + | |
- | ; | + | ATTR_T |
- | ; Limpiar la pantalla con el patron de pixeles indicado. | + | |
- | ; Entrada: | + | |
- | ; | + | |
- | ClearScreen: | + | |
- | LD HL, 16384 ; HL = Inicio del area de imagen | + | |
- | LD (HL), A ; Escribimos el valor de A en (HL) | + | |
- | LD DE, 16385 ; Apuntamos DE a 16385 | + | |
- | LD BC, 192*32-1 | + | |
- | LDIR | + | |
- | RET | + | |
- | + | ||
- | ; | + | |
- | ; Establecer los colores de la pantalla con el byte de atributos indicado. | + | |
- | ; Entrada: | + | |
- | ; | + | |
- | ClearAttributes: | + | |
- | + | ||
- | LD HL, 22528 ; HL = Inicio del area de atributos | + | |
- | LD (HL), A ; Escribimos el patron A en (HL) | + | |
- | LD DE, 22529 ; Apuntamos DE a 22529 | + | |
- | LD BC, 24*32-1 | + | |
- | LDIR ; e incrementamos HL y DL. Restamos 1 | + | |
- | ; porque ya hemos escrito en 22528. | + | |
- | RET | + | |
- | + | ||
- | ; | + | |
- | ; SetBorder: Cambio del color del borde al del registro A | + | |
- | ; Se establece BORDCR tal cual lo requiere BASIC. | + | |
- | ; | + | |
- | SetBorder: | + | |
- | OUT (254), A ; Cambiamos el color del borde | + | |
- | RLCA | + | |
- | RLCA | + | |
- | RLCA ; A = A*8 (colocar en bits PAPER) | + | |
- | BIT 5, A ; Mirar si es un color BRIGHT | + | |
- | JR NZ, SetBorder_fin | + | |
- | ; Si es bright | + | |
- | XOR 7 ; -> cambiar la tinta a 0 | + | |
- | + | ||
- | SetBorder_fin: | + | |
- | LD (23624), A ; Salvar el valor en BORDCR | + | |
- | RET | + | |
- | + | ||
- | ; | + | |
- | ; PrintString: | + | |
- | ; HL = direccion de la cadena de texto a imprimir. | + | |
- | ; | + | |
- | PrintString: | + | |
- | + | ||
- | printstrloop: | + | |
- | LD A, (HL) ; Obtener el siguiente caracter a imprimir | + | |
- | CP 0 ; Comprobar si es un 0 (fin de linea) | + | |
- | RET Z ; Si es cero, fin de la rutina | + | |
- | RST 16 ; No es cero, imprimir caracter o codigo | + | |
- | ; de control (13=enter, etc). | + | |
- | INC HL ; Avanzar al siguiente caracter | + | |
- | JP printstrloop | + | |
- | ret | + | |
- | + | ||
; | ; | ||
; 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 '' |
\\ | \\ | ||
- | {{ cursos: | + | {{ cursos: |
\\ | \\ | ||
- | Nótese que dado lo habitual que puede ser llamar a ClearScreen y ClearAttributes, | + | Cuando |
- | + | ||
- | + | ||
- | <code z80> | + | |
- | ; | + | |
- | ; Limpiar la pantalla con el patron de pixeles y atributos indicado. | + | |
- | ; Entrada: | + | |
- | ; | + | |
- | ClearScreenAttrib: | + | |
- | PUSH DE | + | |
- | PUSH BC | + | |
- | + | ||
- | LD A, H ; A = el atributo | + | |
- | EX AF, AF' | + | |
- | LD A, L ; Cargamos en A el patron | + | |
- | LD HL, 16384 ; HL = Inicio del area de imagen | + | |
- | LD (HL), A ; Escribimos el valor de A en (HL) | + | |
- | LD DE, 16385 ; Apuntamos DE a 16385 | + | |
- | LD BC, 192*32-1 | + | |
- | LDIR | + | |
- | + | ||
- | EX AF, AF' | + | |
- | INC HL ; Incrementamos HL y DE | + | |
- | INC DE ; para entrar en area de atributos | + | |
- | LD (HL), A ; Almacenamos el atributo | + | |
- | LD BC, 24*32-1 | + | |
- | LDIR | + | |
- | + | ||
- | POP BC | + | |
- | POP DE | + | |
- | RET | + | |
- | </ | + | |
- | + | ||
- | + | ||
- | Por otra parte, cuando | + | |
\\ | \\ | ||
===== 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 1167: | Línea 1069: | ||
* Zoom o reducción de alguna zona de pantalla. | * Zoom o reducción de alguna zona de pantalla. | ||
* (etc...). | * (etc...). | ||
- | |||
Por ejemplo, la siguiente rutina vacía el contenido de una pantalla (preferentemente monocolor) haciendo una rotación de los píxeles de cada bloque de pantalla. Los bloques 0-15 verán sus píxeles rotados a la izquierda y los bloques 16-31 a la derecha: | Por ejemplo, la siguiente rutina vacía el contenido de una pantalla (preferentemente monocolor) haciendo una rotación de los píxeles de cada bloque de pantalla. Los bloques 0-15 verán sus píxeles rotados a la izquierda y los bloques 16-31 a la derecha: | ||
Línea 1175: | Línea 1076: | ||
; Fundido de los pixeles a cero con una cortinilla | ; Fundido de los pixeles a cero con una cortinilla | ||
- | | + | |
Start: | Start: | ||
+ | ; Rellenamos la VRAM de pixeles copiando 6 KB de la ROM | ||
+ | ld hl, 0 | ||
+ | ld de, 16384 | ||
+ | ld bc, 6144 | ||
+ | ldir | ||
- | ; Rellenamos la VRAM de pixeles copiando 6 KB de la ROM | + | call Wait_For_Key |
+ | call FadeScreen | ||
- | LD HL, 0 | + | ret |
- | LD DE, 16384 | + | |
- | LD BC, 6144 | + | |
- | LDIR | + | |
- | CALL Wait_For_Keys_Pressed | ||
- | CALL Wait_For_Keys_Released | ||
- | CALL FadeScreen | ||
- | |||
- | RET | ||
- | |||
- | ; | ||
- | Wait_For_Keys_Pressed: | ||
- | XOR A | ||
- | IN A, (254) | ||
- | OR 224 | ||
- | INC A | ||
- | JR Z, Wait_For_Keys_Pressed | ||
- | RET | ||
- | |||
- | ; | ||
- | Wait_For_Keys_Released: | ||
- | XOR A | ||
- | IN A, (254) | ||
- | OR 224 | ||
- | INC A | ||
- | JR NZ, Wait_For_Keys_Released | ||
- | RET | ||
- | |||
; | ; | ||
; Fundido de pantalla decrementando los pixeles de pantalla | ; Fundido de pantalla decrementando los pixeles de pantalla | ||
; | ; | ||
FadeScreen: | FadeScreen: | ||
- | PUSH AF | + | push af |
- | PUSH BC | + | push bc |
- | PUSH DE | + | push de |
- | PUSH HL ; Preservamos los registros | + | push hl ; Preservamos los registros |
- | | + | |
- | LD B, 9 ; Repetiremos el bucle 9 veces | + | ld b, 9 ; Repetiremos el bucle 9 veces |
- | LD C, 0 ; Nuestro contador de columna | + | ld c, 0 ; Nuestro contador de columna |
fadegfx_loop1: | fadegfx_loop1: | ||
- | LD HL, 16384 ; Apuntamos HL a la zona de atributos | + | ld hl, 16384 ; Apuntamos HL a la zona de atributos |
- | LD DE, 6144 ; Iteraciones bucle | + | ld de, 6144 ; Iteraciones bucle |
fadegfx_loop2: | fadegfx_loop2: | ||
- | LD A, (HL) ; Cogemos el grupo de 8 pixeles | + | ld a, (hl) ; Cogemos el grupo de 8 pixeles |
+ | ;-- Actuamos sobre el valor de los pixeles -- | ||
+ | cp 0 ; | ||
+ | jr z, fadegfx_save | ||
- | ;-- Actuamos sobre el valor de los pixeles -- | + | ex af, af |
- | CP 0 ; | + | |
- | JR Z, fadegfx_save | + | |
- | EX AF, AF' | + | ld a, c |
+ | cp 15 ; Comparamos A con 15 | ||
+ | jr nc, fadegfx_mayor15 | ||
- | LD A, C | + | ex af, af |
- | CP 15 ; Comparamos A con 15 | + | |
- | JR NC, fadegfx_mayor15 | + | |
- | + | ||
- | EX AF, AF' | + | |
- | RLA ; Rotamos A a la izquierda | + | |
- | JR fadegfx_save | + | |
fadegfx_mayor15: | fadegfx_mayor15: | ||
- | EX AF, AF' | + | ex af, af |
- | SRL A ; Rotamos A a la derecha | + | srl a ; Rotamos A a la derecha |
- | ;-- Fin actuacion sobre el valor de los pixeles -- | + | |
fadegfx_save: | fadegfx_save: | ||
- | | + | ld (hl), a ; Almacenamos el atributo modificado |
- | INC HL ; Avanzamos puntero de memoria | + | inc hl ; Avanzamos puntero de memoria |
- | ; Incrementamos el contador y comprobamos si hay que resetearlo | + | |
- | INC C | + | inc c |
- | LD A, C | + | ld a, c |
- | CP 32 | + | |
- | JR NZ, fadegfx_continue | + | jr nz, fadegfx_continue |
- | LD C, 0 | + | ld c, 0 |
fadegfx_continue: | fadegfx_continue: | ||
- | DEC DE | + | dec de |
- | LD A, D | + | ld a, d |
- | OR E | + | or e |
- | JP NZ, fadegfx_loop2 | + | jp nz, fadegfx_loop2 |
- | | + | djnz fadegfx_loop1 |
- | POP HL | + | pop hl |
- | POP DE | + | pop de |
- | POP BC | + | pop bc |
- | POP AF ; Restauramos registros | + | pop af ; Restauramos registros |
- | RET | + | ret |
- | END 50000 | + | INCLUDE " |
+ | |||
+ | | ||
</ | </ | ||
Línea 1284: | Línea 1166: | ||
\\ | \\ | ||
- | {{ cursos: | + | {{ cursos: |
\\ | \\ | ||
- | | + | |
A continuación podemos ver la rutina de degradación de atributos que vimos como un ejemplo en el capítulo dedicado a la pila. Este efecto aplicado sobre una pantalla gráfica puede utilizarse como " | A continuación podemos ver la rutina de degradación de atributos que vimos como un ejemplo en el capítulo dedicado a la pila. Este efecto aplicado sobre una pantalla gráfica puede utilizarse como " | ||
Línea 1296: | Línea 1178: | ||
; | ; | ||
FadeAttributes: | FadeAttributes: | ||
- | PUSH AF | + | push af |
- | PUSH BC | + | push bc |
- | PUSH DE | + | push de |
- | PUSH HL ; Preservamos los registros | + | push hl ; Preservamos los registros |
- | | + | |
- | LD B, 9 ; Repetiremos el bucle 9 veces | + | ld b, 9 ; Repetiremos el bucle 9 veces |
fadescreen_loop1: | fadescreen_loop1: | ||
- | LD HL, 16384+6144 | + | ld hl, 16384+6144 |
- | LD DE, 768 ; Iteraciones bucle | + | ld de, 768 ; Iteraciones bucle |
+ | |||
+ | halt | ||
+ | halt ; Ralentizamos el efecto | ||
- | HALT | ||
- | | ||
- | |||
fadescreen_loop2: | fadescreen_loop2: | ||
- | LD A, (HL) ; Cogemos el atributo | + | ld a, (hl) ; Cogemos el atributo |
- | AND 127 | + | and %01111111 |
- | LD C, A | + | ld c, a |
- | AND 7 | + | and %00000111 |
- | JR Z, fadescreen_ink_zero | + | jr z, fadescreen_ink_zero |
- | DEC A ; Si no es cero, decrementamos su valor | + | dec a ; Si no es cero, decrementamos su valor |
fadescreen_ink_zero: | fadescreen_ink_zero: | ||
- | | ||
- | EX AF, AF' | ||
- | LD A, C ; Recuperamos el atributo | ||
- | SRA A | ||
- | SRA A ; Pasamos los bits de paper a 0-2 | ||
- | SRA A ; con 3 instrucciones de desplazamiento >> | ||
- | AND 7 | + | ex af, af ; Nos hacemos una copia de la tinta en A' |
- | JR Z, fadescreen_paper_zero | + | ld a, c |
+ | sra a | ||
+ | sra a ; Pasamos los bits de paper a 0-2 | ||
+ | sra a | ||
- | DEC A ; Lo decrementamos | + | and %00000111 |
+ | jr z, fadescreen_paper_zero | ||
+ | |||
+ | dec a ; Lo decrementamos | ||
fadescreen_paper_zero: | fadescreen_paper_zero: | ||
- | SLA A | + | sla a |
- | SLA A ; Volvemos a color paper en bits 3-5 | + | sla a ; Volvemos a color paper en bits 3-5 |
- | SLA A ; Con 3 instrucciones de desplazamiento << | + | sla a ; Con 3 instrucciones de desplazamiento << |
- | LD C, A ; Guardamos el papel decrementado en A | + | ld c, a ; Guardamos el papel decrementado en A |
- | EX AF, AF' | + | ex af, af |
- | OR C ; A = A OR C | + | or c ; A = A or c |
- | | + | ld (hl), a ; Almacenamos el atributo modificado |
- | INC HL ; Avanzamos puntero de memoria | + | inc hl ; Avanzamos puntero de memoria |
- | DEC DE | + | dec de |
- | LD A, D | + | ld a, d |
- | OR E | + | or e |
- | JP NZ, fadescreen_loop2 | + | jp nz, fadescreen_loop2 |
- | | + | djnz fadescreen_loop1 |
- | POP HL | + | pop hl |
- | POP DE | + | pop de |
- | POP BC | + | pop bc |
- | POP AF ; Restauramos registros | + | pop af ; Restauramos registros |
- | RET | + | ret |
</ | </ | ||
\\ | \\ | ||
- | {{ cursos: | + | {{ cursos: |
\\ | \\ | ||
| | ||
+ | |||
+ | 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. | ||
+ | * Mergear (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 1377: | Línea 1275: | ||
\\ | \\ | ||
- | 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 $A000. 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 $A000. | + | 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 " | ||
- | |||
En el tiempo disponible tras un pulso VSYNC no hay tiempo material para actualizar los 6KB de una pantalla completa sin que el haz de electrones alcance a nuestro programa conforme manipula la memoria, por lo que esta técnica permitiría realizar ese tipo de acciones con el siguiente proceso: | En el tiempo disponible tras un pulso VSYNC no hay tiempo material para actualizar los 6KB de una pantalla completa sin que el haz de electrones alcance a nuestro programa conforme manipula la memoria, por lo que esta técnica permitiría realizar ese tipo de acciones con el siguiente proceso: | ||
\\ | \\ | ||
- | * 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 visibles. 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, | + | 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, |
- | 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 página | + | 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 |
- | Se reseñó también, en el apartado // | + | Se reseñó también, en el apartado // |
\\ | \\ | ||
Línea 1413: | Línea 1311: | ||
\\ | \\ | ||
- | Como puede verse en la figura anterior, los modos Bit2 = 0, Bit3 = 1 (Bancos 4-5-6-3) y Bit2 = 1, Bit 3=1 (Bancos 4-7-6-3) del puerto $1FFD permiten paginar cualquiera de las 2 videorams (RAM5 o RAM7) sobre $A000. | + | 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. |
- | La utilización de cualquiera de estas técnicas | + | Pese a las posibilidades de " |
\\ | \\ | ||
Línea 1437: | Línea 1335: | ||
* {{cursos: | * {{cursos: | ||
* {{cursos: | * {{cursos: | ||
- | + | * {{cursos: | |
\\ | \\ | ||
===== Enlaces ===== | ===== Enlaces ===== | ||
Línea 1445: | Línea 1344: | ||
* [[http:// | * [[http:// | ||
* [[http:// | * [[http:// | ||
- | * [[http:// | ||
\\ | \\ | ||
+ | **[ [[.: | ||