Soporte para interrupciones raster completo

Avatar de Usuario
mcleod_ideafix
Mensajes: 829
Registrado: 27 Sep 2015, 00:14
Ubicación: Jerez de la Frontera
Contactar:

Soporte para interrupciones raster completo

Mensaje por mcleod_ideafix » 07 Dic 2015, 23:32

Esto es algo que se venía pidiendo desde hace ya tiempo, cuando aún debatíamos en ZdP, y sólo hace unas pocas semanas que lo concretamos en conversación entre los miembros del equipo. Pues bien, ya están implementadas las llamadas "interrupciones ráster".

Consiste en poder elegir en qué línea de pantalla queremos disparar una interrupción INT. De esta forma es posible sincronizar más fácilmente lo que hace la CPU con la posición de la exploración de pantalla de la ULA. Esto permite efectos tipo split-screen, borde multicolor, o pintado de más sprites por frame usando algoritmos del tipo "racing the beam".

La forma de hacerlo es usando un par de nuevos registros dentro del bloque designado para ZX-Uno. Uno de ellos permite elegir los 8 bits menos significativos de la línea en la que queremos que se produzca la interrupción. El otro registro guarda el bit noveno del valor de la línea, más un par de bits para habilitar esta interrupción ráster, y opcionalmente, deshabilitar la interrupción habitual por retrazo vertical.

La forma de implementar esta nueva interrupción está inspirada en cómo se hace en el SAM Coupé, y así, el disparo de la señal INT se produce un poco antes de la línea deseada: en concreto el flanco de bajada de INT se produce en el momento en que se termine de pintar la zona de paper de la línea anterior a la pedida, y se comienza a dibujar el borde derecho. Esto da 96 ciclos de reloj desde que ocurre ese flanco hasta que se comienza a pintar la zona de paper de la línea en la que se ha elegido disparar la interrupción ráster. Si se quieren hacer cosas con el borde, hay 80 ciclos de reloj. Esto suponiendo 224 ciclos por linea. Para el modo de 128K, hay 4 ciclos más de reloj disponibles.

El que existan 9 bits en total para definir la línea en la que se dispara la interrupción significa que, a diferencia de lo que ocurre en SAM Coupé, aquí podemos elegir disparar la interrupción ráster no sólamente en las líneas correspondientes al paper, sino en cualquier otra, que puede corresponder al borde superior, inferior, o incluso a la zona de blanking vertical. Se puede por tanto definir una interrupción que se dispare justo después de terminar de pintar el paper (es decir, en la primera línea del borde inferior) y así tener más tiempo que antes para pintar sprites para el siguiente frame.

Los detalles de cómo acceder a esos registros, etc, como siempre, en la wiki técnica.

A modo de demostración, he escrito un progamita que pretende hacer algo parecido a lo que se ve en algunas demos. Seguramente, los mascas que hacen estas demos son capaces de lograr este mismo efecto sin raster interrupts, pero ahora al menos se puede hacer con más desahogo de la CPU, o código menos ofuscado. En la foto no se aprecia que la barra se mueve.
demo_raster_interrupt.jpg
El código fuente y TAP de esta demo, y otra más sencilla, están en la carpeta "raster_tests" dentro de la carpeta del test20. Se ve como el gestor de interrupción ráster se dedica a pintar el borde del color que corresponda según la línea en la que estemos, y un gestor de interrupción de retrazo vertical que prepara los datos para que la ráster no pierda un tiempo precioso, y además tocar 1/50 de música.

Creo que con esto doy por finiquitado el test20. Lo que falta por hacer, para el test21 (salvo que haya alguna cosa que tenga que corregir en éste)
http://www.zxuno.com
ZX-Uno · Clon de ordenador ZX Spectrum basado en FPGA

Avatar de Usuario
Haplo
Mensajes: 367
Registrado: 05 Oct 2015, 13:51
Ubicación: Ciudad Real

Re: Soporte para interrupciones raster completo

Mensaje por Haplo » 07 Dic 2015, 23:52

Grandes noticias, si señor!

uyuyuuyuyuy, me estoy oliendo que algunas cosas se van a simplificar bastante con esto!

A ver si chernandezba tiene un rato y le da soporte en su emulador...

Aunque ya con esto es motivo suficiente para actualizar mi zxuno de una vez y ponerme a curiosear todas estas novedades.

Avatar de Usuario
chernandezba
Mensajes: 832
Registrado: 02 Oct 2015, 23:35

Re: Soporte para interrupciones raster completo

Mensaje por chernandezba » 08 Dic 2015, 11:54

Haplo escribió:Grandes noticias, si señor!

uyuyuuyuyuy, me estoy oliendo que algunas cosas se van a simplificar bastante con esto!

A ver si chernandezba tiene un rato y le da soporte en su emulador...

Aunque ya con esto es motivo suficiente para actualizar mi zxuno de una vez y ponerme a curiosear todas estas novedades.
Si, jeje, otra cosa más que tengo que agregar. Pero el hecho de que se dispare justo después del papel y antes del borde derecho me complica y mucho el core... Tengo que mirar la manera de agregar esto sin tener que meter ningún 'if' en cada ejecución de instrucción para saber cuando se acaba el pintado de papel. Para mí hubiese sido más fácil que se disparase la interrupción cuando se acaba de pintar el borde izquierdo...

En fin, tendré que ver la mejor manera de meter esto sin sobrecargar la cpu.

Saludos
César
----

ZEsarUX
ZX Second-Emulator And Released for UniX
https://github.com/chernandezba/zesarux

Avatar de Usuario
mcleod_ideafix
Mensajes: 829
Registrado: 27 Sep 2015, 00:14
Ubicación: Jerez de la Frontera
Contactar:

Re: Soporte para interrupciones raster completo

Mensaje por mcleod_ideafix » 08 Dic 2015, 13:46

En el momento en que se escriba un valor en RASTERLINE o RASTERCTRL, precalcula en que estado se disparará la interrupción (esto si llevas una cuenta de estados durante la ejecución del programa)
http://www.zxuno.com
ZX-Uno · Clon de ordenador ZX Spectrum basado en FPGA

Avatar de Usuario
chernandezba
Mensajes: 832
Registrado: 02 Oct 2015, 23:35

Re: Soporte para interrupciones raster completo

Mensaje por chernandezba » 08 Dic 2015, 22:22

mcleod_ideafix escribió:En el momento en que se escriba un valor en RASTERLINE o RASTERCTRL, precalcula en que estado se disparará la interrupción (esto si llevas una cuenta de estados durante la ejecución del programa)
Si. Llevo una cuenta de testados. Pero esto representa un 'if' nuevo y cualquier nuevo 'if' en el bucle principal aumenta el uso de cpu. Si fuese al finalizar el borde izquierdo, ya hay una sentencia if que podrá aprovechar.
Pero bueno, lo pensaré...
----

ZEsarUX
ZX Second-Emulator And Released for UniX
https://github.com/chernandezba/zesarux

Avatar de Usuario
mcleod_ideafix
Mensajes: 829
Registrado: 27 Sep 2015, 00:14
Ubicación: Jerez de la Frontera
Contactar:

Re: Soporte para interrupciones raster completo

Mensaje por mcleod_ideafix » 08 Dic 2015, 23:22

chernandezba escribió:Si. Llevo una cuenta de testados. Pero esto representa un 'if' nuevo y cualquier nuevo 'if' en el bucle principal aumenta el uso de cpu. Si fuese al finalizar el borde izquierdo, ya hay una sentencia if que podrá aprovechar.
Pero bueno, lo pensaré...
Piensa que desde hace ya bastantes años, los procesadores disponen de un sistema de predicción de saltos. En el caso del Pentium IV es de hecho muy sofisticado: una "caché de trazas", por lo que el impacto en el rendimiento será muy poco. De todas formas, si quieres, puedes usar unas construcciones del gcc que permiten ayudar al compilador a generar código más eficiente para los condicionales:

Código: Seleccionar todo

if ( unlikely(x) )
{
  loquesea...
}
Ésta, por ejemplo, le dice al compilador que x es una condición que probablemente no se cumpla, así que el compilador genera código para que el salto sólo se produzca cuando la condición sea cierta. Así, cuando la condición no se cumpla, que será la mayoría de las veces, no habrá penalización por salto.

Analogamente existe:

Código: Seleccionar todo

if ( likely(x) )
{
  loquesea...
}
Que asume que x es una condición que casi siempre se va a cumplir

Te hablo de memoria, así que igual no es exactamente así como funcionan, pero las recuerdo de hace ya tiempo...

Más info, aquí:
http://stackoverflow.com/questions/1668 ... space-code
http://www.zxuno.com
ZX-Uno · Clon de ordenador ZX Spectrum basado en FPGA

Avatar de Usuario
chernandezba
Mensajes: 832
Registrado: 02 Oct 2015, 23:35

Re: Soporte para interrupciones raster completo

Mensaje por chernandezba » 09 Dic 2015, 01:00

Gracias! No tenía ni idea de todo esto, qué curioso!
De todas maneras creo que voy a hacer una prueba, medir el uso de cpu en igualdad de condiciones, con el 'if' para detectar la interrupción raster o sin el, a ver si varía algo... Si no noto variación significativa, lo dejo así y listo ;)

Saludos
----

ZEsarUX
ZX Second-Emulator And Released for UniX
https://github.com/chernandezba/zesarux

Avatar de Usuario
chernandezba
Mensajes: 832
Registrado: 02 Oct 2015, 23:35

Re: Soporte para interrupciones raster completo

Mensaje por chernandezba » 16 Dic 2015, 18:51

Hola

Estoy testeando el soporte de raster en ZEsarUX. La demo multicolor se ve bien, la otra que combina dos fotos, no:

https://www.youtube.com/watch?v=YQNRTIM ... e=youtu.be

Olvidaros del desfase de línea de la multicolor, ese es un problema asociado a como dibujo la pantalla y el cambio de color en ULAplus, pero no tiene que ver con el raster.

Varias dudas:
-Entiendo que la interrupción raster no se lanza si las interrupciones no están habilitadas
-El contador de línea, cuenta desde la primera línea visible? O desde donde cuenta? Porque yo de manera aproximada cuento primero, 8 líneas no visibles que no generan border, luego 56 líneas de border, luego el centro de la pantalla, etc
-Con qué timing está pensado para que se use la segunda demo de las fotos? Porque ni probando con 48 o 128 se ve bien
-Entiendo que se lanza la interrupción raster justo al empezar borde derecho, no?

Alguna pista de por que falla?
Saludos
----

ZEsarUX
ZX Second-Emulator And Released for UniX
https://github.com/chernandezba/zesarux

Avatar de Usuario
mcleod_ideafix
Mensajes: 829
Registrado: 27 Sep 2015, 00:14
Ubicación: Jerez de la Frontera
Contactar:

Re: Soporte para interrupciones raster completo

Mensaje por mcleod_ideafix » 19 Dic 2015, 01:49

chernandezba escribió:-Entiendo que la interrupción raster no se lanza si las interrupciones no están habilitadas
Correcto, aunque el registro que indica que se está produciendo una interrupción ráster debe actualizarse de todas formas. Simplemente, si la CPU ha ejecutado DI, obviamente ignorará tales interrupciones (como siempre)
chernandezba escribió:-El contador de línea, cuenta desde la primera línea visible? O desde donde cuenta? Porque yo de manera aproximada cuento primero, 8 líneas no visibles que no generan border, luego 56 líneas de border, luego el centro de la pantalla, etc
El contador de lineas considera que la línea 0 es la primera línea de paper, la linea 192 por tanto es la primera línea de borde inferior. Las dimensiones del borde inferior y superior dependen de los timings seleccionados (luego te pongo tabla) El último valor del contador es 311 si estamos en un 48K, 310 si estamos en 128K, o 319 si estamos en Pentagon, y coincidiría con la última línea del borde superior.
chernandezba escribió:-Con qué timing está pensado para que se use la segunda demo de las fotos? Porque ni probando con 48 o 128 se ve bien
Precisamente la gracia de las interrupciones ráster es conseguir efectos ráster sin depender de los timings de la máquina. El efecto debería verse bien con cualquiera de los timings que soporta ZX-Uno.
chernandezba escribió:-Entiendo que se lanza la interrupción raster justo al empezar borde derecho, no?
Correcto. Con un matiz: justo al comenzar el borde derecho de la línea anterior a aquella que has seleccionado. La razón de esto es que el gestor de interrupción tenga tiempo para hacer algo de "magia" antes de que el borde izquierdo de la línea en la que realmente queremos actuar empiece a pintarse. Recuerda que desde que se dispara la interrupción hasta que le gestor de interrupciones comienza a funcionar pasan unos 20 ciclos aproximadamente. Este es el mecanismo que he copiado del SAM Coupé, en el que el contaje de lineas y píxeles se realiza comenzando por el borde derecho.
chernandezba escribió:Alguna pista de por que falla?
Yo diría que todo se reduce a dónde has supuesto que se toma el valor 0 de la raster interrupt. Ya has visto cómo es. La primera demo, multicolor, es insensible a en qué momento consideres que comienza la linea 0, pero la segunda demo no es insensible a este factor. He añadido información extra en la wiki técnica (que debería haber puesto desde el principio -mea culpa-) que espero sirva para aclarar un poco las cosas.
http://www.zxuno.com
ZX-Uno · Clon de ordenador ZX Spectrum basado en FPGA

Avatar de Usuario
mcleod_ideafix
Mensajes: 829
Registrado: 27 Sep 2015, 00:14
Ubicación: Jerez de la Frontera
Contactar:

Re: Soporte para interrupciones raster completo

Mensaje por mcleod_ideafix » 19 Dic 2015, 03:40

Un par de gráficos para aclarar (espero) el asunto:

El primero muestra un esquema de la temporización de la pantalla. Cada pixel del dibujo es un pixel real generado por la ULA. Las bandas negras a la derecha y abajo corresponden a los intervalos de blanking horizontal y vertical respectivamente. Dentro de ellos, las bandas de color gris claro corresponden a los sincronismos horizontal y vertical respectivamente.
detalle_interrupcion_raster.png
detalle_interrupcion_raster.png (1.34 KiB) Visto 3897 veces
El dibujo está hecho para los timings de un 48K. Esto es, tiene 448 pixeles por 312. Esto son 139776 pixeles. Dado que un ciclo de reloj de CPU son dos pixeles, el tiempo en ciclos de reloj es de 69888 ciclos, que es lo que todo el mundo conoce como tiempo de frame.

Lo que se considera una "linea de pantalla" es lo que está pintado en magenta. Se han pintado dos líneas, la 0 y la 192. La línea 0 es la primera línea en la que se dibuja "paper". La línea 192 es la primera en la que se dibuja borde inferior. Como veis, se considera que una línea comienza tras el pulso de sincronismo horizontal y después de ese pulso y terminar el intervalo de blanking horizontal, continua con el borde izquierdo. Es como si el primer dibujo lo recortáramos y pegáramos el borde derecho con el izquierdo formando un cilindro.
pantalla_enrollada_en_cilindro.jpg
Durante el pulso de sincronismo hay una transición de una línea a la siguiente (ver siguiente detalle)
detalle_paso_de_una_linea_a_la_siguiente.png
Las dos líneas de color blanco intenso del primer dibujo son pulsos de interrupción. El primero está configurado para dispararse en la línea 0 y el segundo en la línea 192. El pulso comienza con el borde derecho y termina 64 píxeles más tarde (32 ciclos de reloj), ya dentro del intervalo de blanking.
http://www.zxuno.com
ZX-Uno · Clon de ordenador ZX Spectrum basado en FPGA

Responder