Estreno nuevo subforo y avances emulador Spectrum dcrespo

Avatar de Usuario
dcrespo3d
Mensajes: 132
Registrado: 04 Nov 2020 08:51
Agradecido : 115 veces
Agradecimiento recibido: 149 veces

Re: Estreno nuevo subforo y avances emulador Spectrum dcrespo

Mensajepor dcrespo3d » 11 Jun 2022 09:49

Último mensaje de la página anterior:

Eremus escribió:
Las ultimas mediciones tras optimizar aquí y allá ya empiezan a pintar bien :)

CPU + VIDEO 18166 / CPU 11801 / VIDEO 6365

Cuando implemente el dibujado del borde, los tiempos subirán un poquillo pero creo que no será demasiado ni nada que no se pueda compensar posteriormente con algunas (o todas -grin) de las mejoras al core de @zx81 que @ackerman ha implementado en su fork.



Esto va teniendo una pinta estupenda. -thumbup

Una vez que tengas implementada la tarea CPU + vídeo, con la mejor optimización posible (cuanto más tiempo sobre, mejor) habría que incluir esperas para que el sonido del beeper suene lo mejor posible. Vamos, que la ejecución de cada instrución en el ciclo se realice en el momento más parecido posible a la máquina real. Cuando las tareas de CPU y vídeo estaban separadas, tenía en la tarea CPU unos delays (#define PER_INSTRUCTION_TIMING) que en realidad no hacian delay cada instrucción, sino cuando habían transcurrido un cierto número de tstates que eran ajustables, lo dejé a 50 y en esa situación iba bien. Pero sobraba mucho tiempo en la tarea de CPU y ahora en la tarea de CPU+vídeo va a sobrar menos... Si por lo menos se pudiera hacer una espera una vez por scanline (224 tstates), puede que estuviera bien, aunque el sonido PWM es muy sensible a las irregularidades en temporización.

Yo probé con la música introductoria del Arkanoid y con la demo pitstop / star tip 2 de Tim Follin. -harp
http://craigsretrocomputingpage.eu5.org ... xdump.html
DavidPrograma en YouTube, GitHub

ackerman
Mensajes: 313
Registrado: 05 Feb 2019 21:32
Ubicación: Asturias
Agradecido : 129 veces
Agradecimiento recibido: 254 veces

Re: Estreno nuevo subforo y avances emulador Spectrum dcrespo

Mensajepor ackerman » 11 Jun 2022 11:00

Vas por muy buen camino @Eremus, te paso pequeños trucos, que imagino habrás visto por mi código (el diablo está en los detalles):

El ESPectrum::vga.backBuffer que llamas en ALU_video, tanto en Bitluni, como fabgl o la versión de Ricardo Massaro, está pensado para que devuelva el puntero al array de punteros de scanlines de un array de doble buffer, es decir, que devuelva el activo en cada momento, 0 o 1. Como no se usa el doble buffer, no se necesita saber el activo, es decir, se puede pillar al principio el directo y se ahorra uno el acceso a métodos de objetos, ganando en velocidad y entrada en caché, por ser un puntero básico:

Código: Seleccionar todo

unsigned char ** gb_buffer_vga;
unsigned int **gb_buffer_vga32;

void setup()
{
 ...
 gb_buffer_vga = vga_get_framebuffer();
 gb_buffer_vga32=(unsigned int **)gb_buffer_vga;
}


No me acuerdo exactamente, pero juraría que lo que es el decode de CPU en 20 ms de frame, debería andar en 10000 llamadas a instrucciones, donde las escrituras a zona de memoria a video, que dependerá del juego, andará entre 2000 y 3000, así que las veces que se llame a la ALU_video, tendrá que lidiar con ello. Por eso, cuanto más elemental sea la función, y menos veces se llame, más velocidad.

Eremus escribió:En otras ocasiones, cambias el tipo de una variable en plan "me aburro no sé ya que hacer" e inexplicablemente (al menos para mi): !zas¡ 100 microsegundos mas rápido. Esto de rascar microsegundos está resultando adictivo y desesperante a la vez -grin

Tiene fácil explicación. Cambiar un tipo a unsigned int (32 bits), el compilador intentará adaptarlo a un registro, si anda sobrado de recursos. El registro es lo más rápido del mundo. Si no se va sobrado de recursos, lo meterá en memoria, que puede entrar en caché o no, es decir, más lento.
Usar unsigned char (8 bits), hay posibilidades de entrar en registro, y en el peor de los casos, caché. La caché es limitada, 4 KB y para todo, así que mejor andar con datos de menos de 4 KB. Así que si se puede tener un array de unsigned char, mejor que unsigned short int o unsigned int.
Un contador unsigned long (64 bits) es más lento que un unsigned int (32 bits) en un ESP32, por consumir más RAM (caer fuera de la caché) y por no ser del tipo del procesador (32 bits). Si se llama muchas veces, pues ...
El código se ejecuta en FLASH, 40 u 80 Mhz, dependiendo del tipo de ESP32. Cuando entra en la caché RTOS SRAM0, el código se ejecutará más rápido, pero para que nos hagamos una idea, el core LKF juraría que eran 100 KB y el de @zx81(José Luis Sánchez) 300 KB. Ambos se salen de los 96KB a 128 KB de SRAM0 de caché de RTOS, así que siempre en algún momento habrá penalización.
Y luego está el DMA para la VGA. El DMA es la mayor chapuza que se ha inventado, pero es barata. Lo que permite, es transferencia de datos entre memoria sin intervenir CPU. Es muy bonito de decir, pero en la realidad se traduce, que mientras se está usando, está bloqueado el bus externo, así que sólo puedes hacer operaciones básicas en paralelo con la CPU o la caché de 4KB, pero no puedes ir más arriba. Lo mismo le sucede al coprocesador.
Todo el volcado de la VGA de bitluni se hace por I2S con DMA en cada scanline, y saltando en los timings de la VGA. Por tanto, siempre que accedamos al puntero a los scanlines, tanto para leer como escribir, si por el medio ha saltado el volcado VGA, tendremos penalización. Soluciones, hay muchas, pero la más sencilla, accesos lo más rápido posible y con montos de tamaño adecuado.

Todo esto, que suena a ladrillo, se traduce, en que optimizar, no es sólo bajar los tiempos de una rutina. Puedes hacer la prueba por ejemplo a una rutina de un simple programa vacio que haga un memcpy en un bloque de memoria, para entender todo esto. Una vez medido, lo llevas a un programa ya grande, por ejemplo, el emulador, y cuando veas los resultados, te explotará la cabeza. En el primer caso, el código al ser el programa tan simple, lo meterá todo, pero todo todo en SRAM0, y todo caerá en caché y registros, y por tanto, los resultados serán 100 y 1000 veces más rápido que el programa grande.

Luego está el tema del compilador, que cada día PlatformIO está cambiando de versión o de usar el IDE de Arduino, y por tanto, las optimizaciones al ser C, cambian. Yo lo preparé para ARDUINO IDE y para PlatformIO, incluidas versiones viejas. No se exactamente, si el que usas actualmente lo está. Si sólo usas binarios compilados, te daría igual.

El mismo @ackerman se desmintió a si mismo posteriormente y con resultados brillantes pero me ha hecho gracia leerlo

Si, la verdad, que por ese hilo, está toda la hemeroteca. Con más tiempo, haber si puedo ir sacando la info e ir metiéndola más ordenada en el subforo.
Si, el emulador original de @rampa, Jorge Fuentes y posteriormente por @dcrespo3d (David Crespo Tascón), al necesitar 18 ms de volcado de video, quedan sólo 2 ms para decode de CPU, lo cual se traduce en imposible en un sólo core, de ahi que usaran 2.

Avatar de Usuario
Eremus
Mensajes: 42
Registrado: 01 May 2022 18:10
Agradecido : 67 veces
Agradecimiento recibido: 73 veces

Re: Estreno nuevo subforo y avances emulador Spectrum dcrespo

Mensajepor Eremus » 14 Jun 2022 18:45

Muy buenas retrowikiers! ;)

Hoy he podido sentarme un poquito a pegarle un empujón a esto y ya he implementado el dibujado del borde. Tras algún traspiés aquí y allá, he conseguido lo fácil (Aquaplane perfecto al 100%):

IMG_20220614_180606.jpg
IMG_20220614_180606.jpg (71.21 KiB) Visto 590 veces

Me ha dado por probar algo que hiciera cosas con el borde y he usado Bordertrix ( https://spectrumcomputing.co.uk/entry/2 ... BorderTrix ). Aqui la cosa ya se ha puesto mas peliaguda. En principio los resultados no eran malos del todo pero no eran perfectos. Esto me ha llevado a implementar la I/O contention para ver si mejoraban los resultados y parece que algo influyen pero no lo suficiente para cuadrar las cosas al 100% aunque tampoco tengo claro que mi implementación sea correcta. En el repo la dejo (funciones ula_contend_port_early y ula_contend_port_late en CPU.cpp) por si quereis verla u opinar. Aqui una imagen sin contended I/O (con la contended activada la cosa cambia muy poquito: las letras del borde superior e inferior se desplazan a la izquierda uno o dos bloques):

IMG_20220614_172150.jpg
IMG_20220614_172150.jpg (119.86 KiB) Visto 590 veces

La imagen tiene algo de truco si sois observadores: modifique la función de dibujado para dibujar menos main screen y asi poder mostrar 24 pixeles de borde inferior ya que la resolución de pantalla que uso es de 360x200. La imagen, comparada con Fuse y RVM en mi ordenador y con algunos videos de Youtube, parece bastante cercana al resultado supuestamente correcto aunque es complicado saberlo porque es muy dependiente de emulador, FPGA o maquina real donde corre.

Si sabéis de alguna demo o juego que pueda probar para testar la sincronización del borde decídmelo por favor (o probadlo vosotros y me contáis).

En resumen y visto lo visto, voy a implementar un dibujado de borde mas sencillo y dejar el dibujado "avanzado" apartado por ahora ya que supone una buena sobrecarga para la función de dibujo y, dado que la cantidad de borde que muestra el emu no es muy generosa, no tiene mucho sentido perder microsegundos en esto.

Por último, vamos con algunos mensajes de nuestros oyentes: -grin

ackerman escribió:El ESPectrum::vga.backBuffer que llamas en ALU_video, tanto en Bitluni, como fabgl o la versión de Ricardo Massaro, está pensado para que devuelva el puntero al array de punteros de scanlines de un array de doble buffer, ...
.
.
... así que las veces que se llame a la ALU_video, tendrá que lidiar con ello. Por eso, cuanto más elemental sea la función, y menos veces se llame, más velocidad.

Esto, nada mas optimice la parte nueva del borde y adapte la función de dibujado a 4:3 y 16:9, quiero hacerlo. Incluso cambiar la librería entera de video por la versión recortada (siempre que a David le parezca bien y no rompamos nada :) )

ackerman escribió:Tiene fácil explicación ...

Fácil, fácil no se yo -grin pero, en todo caso, muy interesante como siempre. Muchas gracias ;)

dcrespo3d escribió:Si por lo menos se pudiera hacer una espera una vez por scanline (224 tstates), puede que estuviera bien, aunque el sonido PWM es muy sensible a las irregularidades en temporización.

Una espera cada 224 tstates igual es demasiado pero no cuesta nada probar. Yo había pensado en una al final de cada frame aunque creo que eso ya lo habías probado tu antes y no resultaba muy bien.

Nada mas por el momento, Saludos!!

Avatar de Usuario
dcrespo3d
Mensajes: 132
Registrado: 04 Nov 2020 08:51
Agradecido : 115 veces
Agradecimiento recibido: 149 veces

Re: Estreno nuevo subforo y avances emulador Spectrum dcrespo

Mensajepor dcrespo3d » 14 Jun 2022 21:46

Eremus escribió:Hoy he podido sentarme un poquito a pegarle un empujón a esto y ya he implementado el dibujado del borde. Tras algún traspiés aquí y allá, he conseguido lo fácil (Aquaplane perfecto al 100%):


Enhorabuena, tiene muy buena pinta. -thumbup

Eremus escribió:Me ha dado por probar algo que hiciera cosas con el borde y he usado Bordertrix ( https://spectrumcomputing.co.uk/entry/2 ... BorderTrix ). Aqui la cosa ya se ha puesto mas peliaguda. En principio los resultados no eran malos del todo pero no eran perfectos. Esto me ha llevado a implementar la I/O contention para ver si mejoraban los resultados y parece que algo influyen pero no lo suficiente para cuadrar las cosas al 100% aunque tampoco tengo claro que mi implementación sea correcta. En el repo la dejo (funciones ula_contend_port_early y ula_contend_port_late en CPU.cpp) por si quereis verla u opinar. Aqui una imagen sin contended I/O (con la contended activada la cosa cambia muy poquito: las letras del borde superior e inferior se desplazan a la izquierda uno o dos bloques):


Depende de si el código que pinta el borde está ejecutándose o no desde memoria baja. En ese ejemplo, tiene pinta de que se ha pintado el bitmap y después se está pintando el borde haciendo un OUT, aunque ahora que lo pienso dependiendo del tstate igual afecta la contended I/O...

Eremus escribió:La imagen tiene algo de truco si sois observadores: modifique la función de dibujado para dibujar menos main screen y asi poder mostrar 24 pixeles de borde inferior ya que la resolución de pantalla que uso es de 360x200. La imagen, comparada con Fuse y RVM en mi ordenador y con algunos videos de Youtube, parece bastante cercana al resultado supuestamente correcto aunque es complicado saberlo porque es muy dependiente de emulador, FPGA o maquina real donde corre.


Cuando lo implementes a 320x240 tendrás 24 por arriba y 24 por abajo -grin

Eremus escribió:Si sabéis de alguna demo o juego que pueda probar para testar la sincronización del borde decídmelo por favor (o probadlo vosotros y me contáis).


Sólo recuerdo Sentinel...

Eremus escribió:En resumen y visto lo visto, voy a implementar un dibujado de borde mas sencillo y dejar el dibujado "avanzado" apartado por ahora ya que supone una buena sobrecarga para la función de dibujo y, dado que la cantidad de borde que muestra el emu no es muy generosa, no tiene mucho sentido perder microsegundos en esto.



Es tu código y tu decisión, para eso te lo estás currando :wink:

Eremus escribió:Una espera cada 224 tstates igual es demasiado pero no cuesta nada probar. Yo había pensado en una al final de cada frame aunque creo que eso ya lo habías probado tu antes y no resultaba muy bien.

Nada mas por el momento, Saludos!!


Una ventaja de ser músico aficionado es que puedo (hasta cierto punto) detectar ciertos patrones temporales erróneos en la temporización únicamente escuchando el sonido del beeper.

Una espera al final del frame se puede cargar por completo el sonido del beeper. Suponte que tardas 15ms en emular un frame y luego esperas 5ms... pues los tonos sonarán acelerados un 33% (20/15), lo cual es casi una cuarta justa (Un Do4 sonaría como un Fa4). Además, ese silencionç de 5ms cada 20ms sería un corte en el audio a 50Hz... te garantizo que sonaría fatal.

En mi ajuste encontré un buen compromiso entre calidad de sonido y número de esperas haciendo una espera cada aproximadamente 50 tstates... esperando cada 224 tstates empeorará el sonido, pero espero que no demasiado.

Juegos para probar:

Zorro tiene una melodía monofónica que tiene que sonar sin cortes (casi son pitidos del beeper). Tienen que sonar los tonos limpios.

Arkanoid tiene al polifonía de dos voces hecha con pwm, pero se distinguen bastante bien las dos líneas, bajo y melodía. Cuando peor la temporización, más sucio y ruidoso el audio. Puedes comparar con otros emuladores.

Por cierto, también tienes el emulador online qaop:
http://torinak.com/qaop#!arkanoid

F1 para menú, incorpora muchos juegos.

Skool Daze tiene un a melodía inicial estridente y un timbre de comienzo de las clases que debe sonar estridente pero uniforme.
http://torinak.com/qaop#!skooldaze
DavidPrograma en YouTube, GitHub

Avatar de Usuario
Eremus
Mensajes: 42
Registrado: 01 May 2022 18:10
Agradecido : 67 veces
Agradecimiento recibido: 73 veces

Re: Estreno nuevo subforo y avances emulador Spectrum dcrespo

Mensajepor Eremus » 15 Jun 2022 15:30

dcrespo3d escribió:Cuando lo implementes a 320x240 tendrás 24 por arriba y 24 por abajo -grin
Sólo recuerdo Sentinel...

https://youtu.be/-EzuZAGtiZQ -thumbup

En todo caso esto es una implementación de prueba para conseguir lo del borde. Por ahora he dejado una función que dibuja el borde de manera mas eficiente (sin soporte lógicamente de border effects) y con el aspect ratio seleccionable, que ya he implementado.

Los tiempos ahora mismo son bastante buenos. He conseguido que no afecte demasiado a los mejores tiempos que obtuve sin dibujar borde ni selección de aspect ratio:

CPU + VIDEO (360x200 16:9) 19126
CPU + VIDEO (320x240 4:3) 19169

Considerando que esto es en la pantalla inicial de DreamWalker, que debido al motor Nirvana actualiza bastante la pantalla, no esta mal del todo. En otras cosas que no machacan tanto la pantalla, el emu va sobrado :)

Ahora a por la temporización:

dcrespo3d escribió:En mi ajuste encontré un buen compromiso entre calidad de sonido y número de esperas haciendo una espera cada aproximadamente 50 tstates... esperando cada 224 tstates empeorará el sonido, pero espero que no demasiado.

Arkanoid tiene al polifonía de dos voces hecha con pwm, pero se distinguen bastante bien las dos líneas, bajo y melodía. Cuando peor la temporización, más sucio y ruidoso el audio. Puedes comparar con otros emuladores.


He probado el Arkanoid y, tal y como explicas, suena fatal sin temporización. Ademas, y eso es nuevo, resulta que se cuelga justo al empezar la partida. Al principio he pensado que podria ser algo relacionado con los cambios a monohilo pero tambien ocurre en la versión multihilo asi que ni idea de que lo produce.

Lo que me ha pasado por la cabeza asi en plan rapido y sin tener ni idea de la generación de sonido, es usar el otro core para el sonido ¿Puede ayudar en algo o he dicho una burrada?

Saludos ;)

Avatar de Usuario
zx81
Mensajes: 469
Registrado: 23 Feb 2013 21:31
Agradecido : 86 veces
Agradecimiento recibido: 223 veces

Re: Estreno nuevo subforo y avances emulador Spectrum dcrespo

Mensajepor zx81 » 15 Jun 2022 16:16

Eremus escribió:He probado el Arkanoid y, tal y como explicas, suena fatal sin temporización. Ademas, y eso es nuevo, resulta que se cuelga justo al empezar la partida. Al principio he pensado que podria ser algo relacionado con los cambios a monohilo pero tambien ocurre en la versión multihilo asi que ni idea de que lo produce.


Stupendom, apuesto a que acabas de descubrir el bus flotante. El Arkanoid, el Sidewize, el Cobra (versión inicial, no la tuneada para +3) usan el bus flotante para saber cuando el haz de electrones ha llegado a la zona de pantalla. En general, no funcionará ningún juego de los que hubo que parchear para el +3 precisamente por no tener el mismo tipo de bus flotante (que durante mucho tiempo se pensó que no tenía y resultó que sí, pero muy diferente). Si cambias la versión del Arkanoid por una de esas, verás como sí funciona.

Respecto al sonido yo usaba mucho para el beeper, además del Arkanoid, el Babaliba (es un tono simple pero que suele producir unos armónicos chirriantes de esos que provocan derrames cerebrales masivos), Fairlight, Terra Cresta, Ping Pong, Uridium, Mad Mix Game-.. hay unos cuantos muy bordes, alguno obra de Tim Follin.

Cuando entras en las músicas polifónicas a base de PWM te das cuenta de que se hacen cambios en el estado del beeper cada 40 t-estados o menos, y eso da muchos dolores de cabeza, además de otitis salvajes. Avisados estáis. -rofl
Cuando utilizo una palabra, esa palabra significa, exactamente, lo que yo quiero que signifique. Ni más, ni menos.
Humpty Dumpty

Empieza a jugar sin tener que compilar: Emulador JSpeccy
ZX Spectrum bare-metal para Raspberry PI ZXBaremulator

Avatar de Usuario
dcrespo3d
Mensajes: 132
Registrado: 04 Nov 2020 08:51
Agradecido : 115 veces
Agradecimiento recibido: 149 veces

Re: Estreno nuevo subforo y avances emulador Spectrum dcrespo

Mensajepor dcrespo3d » 15 Jun 2022 16:41

Eremus escribió:https://youtu.be/-EzuZAGtiZQ -thumbup
En todo caso esto es una implementación de prueba para conseguir lo del borde. Por ahora he dejado una función que dibuja el borde de manera mas eficiente (sin soporte lógicamente de border effects) y con el aspect ratio seleccionable, que ya he implementado.
Los tiempos ahora mismo son bastante buenos. He conseguido que no afecte demasiado a los mejores tiempos que obtuve sin dibujar borde ni selección de aspect ratio:

CPU + VIDEO (360x200 16:9) 19126
CPU + VIDEO (320x240 4:3) 19169

Considerando que esto es en la pantalla inicial de DreamWalker, que debido al motor Nirvana actualiza bastante la pantalla, no esta mal del todo. En otras cosas que no machacan tanto la pantalla, el emu va sobrado :)


Qué pena no poder tener las dos cosas, efectos de borde y emulación rápida (< 20ms)

Eremus escribió:He probado el Arkanoid y, tal y como explicas, suena fatal sin temporización. Ademas, y eso es nuevo, resulta que se cuelga justo al empezar la partida.
Al principio he pensado que podria ser algo relacionado con los cambios a monohilo pero tambien ocurre en la versión multihilo asi que ni idea de que lo produce.


El fallo del Arkanoid es porque utiliza una técnica oscura (lectura del bus flotante) para evitar tearing en el dibujo. Tienes más info en
https://spectrumforeveryone.com/technic ... ating-bus/
y en "la palabra revelada" -mf_popeanim
https://worldofspectrum.org/faq/referen ... erence.htm
buscando el texto "Arkanoid".

El Arkanoid original que sacaron en 48K se quedaba congelado en un 128K debido a que el bus flotante no se comporta igual en los dos sistemas. De hecho sacaron una versión corregida que sí funcionaba en el 128K.

Eremus escribió:Lo que me ha pasado por la cabeza asi en plan rapido y sin tener ni idea de la generación de sonido, es usar el otro core para el sonido ¿Puede ayudar en algo o he dicho una burrada?


Pues al principio me ha parecido una burrada, pero luego lo he pensado mejor y quizás ya no tanto... -grin

Lo primero que he pensado ha sido una burrada, que era ejecutar en el segundo core la tarea de CPU sin generación de vídeo... es una burrada de las gordas por muchos motivos, porque la tarea de CPU afecta a la memoria, habría que tener 2 copias de la RAM, etc... por ahí no sigo.

Pero quizás una posibilidad sería rellenar un buffer de audio en la tarea CPU+vídeo con la temporización adecuada (tenemos los TStates y sabemos qué muestras del buffer habría que rellenar) y reproducir ese buffer con esperas en una tarea en el otro core.

Tendríamos que usar doble buffer (el core 1 rellena un buffer y el core 2 reproduce el otro buffer) con lo que introduciríamos 20 ms de retardo en el audio, cosa que no me encanta, pero sería asumible.

Para conseguir mayor calidad en el sonido pwm, habría que tener un buffer cuando mayor mejor, pero sin pasarse.

Si tenemos una muestra cada 224 tstates, tendríamos 312 muestras. La frecuencia de muestreo sería de 312·50 = 15600 y la frecuencia máxima de audio la mitad, 7800. Es poco, no sonaría bien.

Pero podríamos perfilar el algoritmo para rellenar el buffer a partir de aquí, dividiendo el tstate entre 224, tendríamos el índice de la muestra correspondiente al tstate.

Podríamos usar un buffer de 312x4 = 1248 o 312x7 = 2184 (uso 4 o 7 porque son divisores de 224). Con 2184 tendríamos 32 tstates de resolución (por debajo de los 40 que recomienda @zx81), y con 1248 tendríamos 56 tstates de resolución que puede que fuera suficiente.

Lo jodido es hacer un algoritmo que a partir del tstate actual y del estado del bit de audio vaya rellenando el buffer de audio sin penalizar el tiempo de la tarea CPU+Video...

Puede que sea demasiado complicado. Me gusta mucho más cómo se hacía hasta ahora, con las esperas.
DavidPrograma en YouTube, GitHub

Avatar de Usuario
dcrespo3d
Mensajes: 132
Registrado: 04 Nov 2020 08:51
Agradecido : 115 veces
Agradecimiento recibido: 149 veces

Re: Estreno nuevo subforo y avances emulador Spectrum dcrespo

Mensajepor dcrespo3d » 16 Jun 2022 20:52

Hola, he hecho un pequeño cambio en el repo, en concreto en el propósito de las ramas.

Ahora la rama master (https://github.com/dcrespo3d/ZX-ESPectrum-Wiimote) es la rama dedicada para la placa Lilygo TTGo VGA32 v1.4 que es la que usa la mayoría de la gente con este proyecto.

La antigua rama lilygo-ttgo-vga32 (https://github.com/dcrespo3d/ZX-ESPectr ... ttgo-vga32) la conservo por motivos históricos (links que apuntan a ella), pero ya no va a ser actualizada más.

Para mi cacharro spectrum custom (un teclado PS2 al que le embutí un devkit ESP32 y le puse conectores VGA, USB, jack y convertidores lógicos de niveles para PS2) me reservo la rama devkit-custom.

Creo que el cambio es a mejor, no tenía sentido no usar la rama master para la lilygo, teniendo en cuenta que es lo que todo el mundo usa.
DavidPrograma en YouTube, GitHub

Avatar de Usuario
Eremus
Mensajes: 42
Registrado: 01 May 2022 18:10
Agradecido : 67 veces
Agradecimiento recibido: 73 veces

Re: Estreno nuevo subforo y avances emulador Spectrum dcrespo

Mensajepor Eremus » 17 Jun 2022 14:32

zx81 escribió:Stupendom, apuesto a que acabas de descubrir el bus flotante.

Conocía el concepto de oídas pero no me había interesado aun por los detalles. Ahora que veo que tiene su interés, cuando tenga un rato probare a implementarlo con ayuda de este post que lo explica muy bien: https://softspectrum48.weebly.com/notes ... oating-bus

zx81 escribió:Si cambias la versión del Arkanoid por una de esas, verás como sí funciona.

En efecto -thumbup Tras localizar y probar la re-release del Arkanoid, ha funcionado a la perfección. Muchas gracias ;)

zx81 escribió:... armónicos chirriantes de esos que provocan derrames cerebrales masivos ... dolores de cabeza, además de otitis salvajes. Avisados estáis. -rofl

Bueno, si no me he quedado sordo tras horas y horas de cabina ( valenciano y dj: soy un cliché con patas -rofl ) con mis Senheisser HD-25 a todo meter ya es poco probable que ocurra. De todas formas, David tiene mucho mas oído y experiencia con el beeper que yo así que la palabra final, en lo que a calidad de emulación del sonido respecta, se la dejo a el.

dcrespo3d escribió:... Puede que sea demasiado complicado. Me gusta mucho más cómo se hacía hasta ahora, con las esperas.

Lo del buffer se puede probar a ver que tal. Ahora mismo, el mejor sonido que he obtenido en mi versión monohilo es con tu temporización CPU_PER_INSTRUCTION_TIMING. He estado probando distintas ideas de temporización pero ninguna mejora la calidad de sonido de tu implementación. En todo caso, en mis pruebas, me ha dado la sensación de que, en ocasiones o en determinados escenarios, genera mas esperas de las necesarias. Sea como sea, es la mejor opción hasta la fecha así que es la que voy a dejar en la versión que he publicado hace un rato ( https://github.com/EremusOne/ZX-ESPectr ... e/monohilo ) y de la que os cuento un poco:

- He dejado dos funciones de dibujo: una que soporta efectos de borde (Solo a 4:3 ya que a 16:9 solo hay 4 pixeles de borde y no tiene sentido) y otra que soporta multicolor pero no efectos de borde. Se puede seleccionar cual se quiere usar en hardconfig.h. Lógicamente, la versión de efectos de borde es mas lenta.

- El rendimiento actual sin efectos de borde está bastante bien. Bastantes juegos dan los 50 fps sin problema y los juegos que usan multicolor pueden estar un poquito por debajo (47-49 fps). (He añadido la opción en hardconfig.h de contar los fps).

- He aseado bastante el código, recolocando algunas cosas aquí y allá y optimizando las cosas en la medida de mis posibilidades. He retirado el soporte para el core Z80 de Lin Ke-Fong ya que no implementa delay contention que es necesario para multicolor y efectos y, además, prefiero usar el de @zx81 que es de la casa -grin

- Creo que añadiré la opción de compilar una versión sin soporte multicolor, mas próxima a la versión inicial del emulador, por dos razones: habrá usuarios que no la necesiten con lo que podrán usar un emu mucho mas eficiente y podré comparar tiempos con la versión multihilo en condiciones mas similares.

Mi TO-DO list de ahora en adelante, por orden de prioridad:

- OSD en pantalla para mostrar, en tiempo real, estado de la carga de cinta entre otras cosas.
- Implementar emulación de bus flotante.
- Comprobar y realizar las adaptaciones necesarias para que las mejoras en multicolor y efectos de borde funcionen bien en las ROMS 128K.

Sin prioridad especial pero importante:

- Temporización lo mas precisa y con el menor impacto posible al rendimiento.
- Mejorar la calidad de sonido del beeper.

Y por ultimo, prioridad en modo TOC -grin

- Optimizar, optimizar y después optimizar un poco mas -rofl

Saludos a todos! ;)

Avatar de Usuario
dcrespo3d
Mensajes: 132
Registrado: 04 Nov 2020 08:51
Agradecido : 115 veces
Agradecimiento recibido: 149 veces

Re: Estreno nuevo subforo y avances emulador Spectrum dcrespo

Mensajepor dcrespo3d » 18 Jun 2022 22:08

Eremus escribió:- El rendimiento actual sin efectos de borde está bastante bien. Bastantes juegos dan los 50 fps sin problema y los juegos que usan multicolor pueden estar un poquito por debajo (47-49 fps). (He añadido la opción en hardconfig.h de contar los fps).


En realidad va mejor que eso, si desactivamos las esperas. Sin esperas el DreamWalker va a 53fps, lo cual significa que nos sobra un poquito de tiempo (más de 1000 microsegundos)

Sólo hay que hacer una espera al final del ciclo para que cada ciclo tarde lo que debe tardar y vala a 50fps. (la que está justo ántes del interruptPending = true del final del ciclo de CPU).

Lo único que habría que hacer es rellenar el buffer de audio, y en la tarea aparte reproducirlo. Mejor con doble buffer de momento.

Estoy haciendo una tontativa -beta

He recuperado el videoTask, lo he llamado audiotask y estoy tratando de que suene. De momento suena como el culo, pero ya suena y eso es algo. La tarea de CPU rellena el buffer y la tarea de audio lo reproduce como puede, la pobre

He pasado tu rama monohilo a mi repo, debo haberlo hecho bien porque sales tú como autor de tus commits -grin

Cuando tenga algo lo subo!
DavidPrograma en YouTube, GitHub

Avatar de Usuario
dcrespo3d
Mensajes: 132
Registrado: 04 Nov 2020 08:51
Agradecido : 115 veces
Agradecimiento recibido: 149 veces

Re: Estreno nuevo subforo y avances emulador Spectrum dcrespo

Mensajepor dcrespo3d » 19 Jun 2022 02:00

-groupwave

Tenemos sonido del beeper bastante decente!!! Aún es un poco sucio (creo que hay microcortes cada 20 milisegundos) pero la frecuencia es correcta y los tonos no me suenan desafinados -drinks

Y todo esto, @Eremus, con tu código con soporte multicolor, sin esperas periódicas!!! -biggrin

Me queda limpiar un poco más el código, y tratar de afinar lo de los microcortes, pero eso lo dejo para otro día.

Eremus escribió:Lo del buffer se puede probar a ver que tal. Ahora mismo, el mejor sonido que he obtenido en mi versión monohilo es con tu temporización CPU_PER_INSTRUCTION_TIMING. He estado probando distintas ideas de temporización pero ninguna mejora la calidad de sonido de tu implementación. En todo caso, en mis pruebas, me ha dado la sensación de que, en ocasiones o en determinados escenarios, genera mas esperas de las necesarias.


He eliminado por completo CPU_PER_INSTRUCTION_TIMING. Ya sólo hay una espera al final del frame para que dure lo que debe durar.

Al final uso dos buffers para el audio: un buffer de producción que rellena la task CPU y otro buffer de consumo que rellena la task de audio. En el momento adecuado se hace el swap de buffers, pero lo tengo que estudiar, creo que el origen de los microcortes no está en el swap sino en la temporización (en los huecos entre ciclos que no están bien temporizados).

Te he hecho un pull request a tu rama monohilo para que puedas probarlo. He intentado dejarlo ordenado pero hoy ya se me acaba la energía y lo ordenaré otro día, y trataré de mitigar los microcortes.

Si álguien más quiere probarlo (aunque aún está verde), está en https://github.com/dcrespo3d/ZX-ESPectr ... e/monohilo
DavidPrograma en YouTube, GitHub

Avatar de Usuario
Eremus
Mensajes: 42
Registrado: 01 May 2022 18:10
Agradecido : 67 veces
Agradecimiento recibido: 73 veces

Re: Estreno nuevo subforo y avances emulador Spectrum dcrespo

Mensajepor Eremus » 19 Jun 2022 04:04

dcrespo3d escribió:-groupwave

Tenemos sonido del beeper bastante decente!!! Aún es un poco sucio (creo que hay microcortes cada 20 milisegundos) pero la frecuencia es correcta y los tonos no me suenan desafinados -drinks

Y todo esto, @Eremus, con tu código con soporte multicolor, sin esperas periódicas!!! -biggrin

Me queda limpiar un poco más el código, y tratar de afinar lo de los microcortes, pero eso lo dejo para otro día.

Ole! Ole! -thumbup Mañana lo pruebo y comentamos/comparamos que no te vas a creer en que he estado trabajando hoy -rofl

Para que te hagas una idea: toma de muestras y reproducción a 48000Khz 8 bits con un filtro 8-tap (sea lo que sea eso) para que suene mas analógico -grin ( Idea sacada de: https://yass.speccy.org/Tutorial/Capitulo7.html ).

He subido el experimento a mi repo en una nueva rama llamada audio-test: https://github.com/EremusOne/ZX-ESPectr ... audio-test

Lo dicho mañana te cuento que me estoy jugando que mi mujer me pida el divorcio si no me voy a la cama ya. Y de batería también ando justito.

ackerman
Mensajes: 313
Registrado: 05 Feb 2019 21:32
Ubicación: Asturias
Agradecido : 129 veces
Agradecimiento recibido: 254 veces

Re: Estreno nuevo subforo y avances emulador Spectrum dcrespo

Mensajepor ackerman » 19 Jun 2022 12:09

Enhorabuena -drinks -drinks . Tiene muy buena pinta.
Por si os sirve, dado que es más ajustes de sincronismo,que potencia de CPU (en tiempo muertos se tiene), si realmente queréis usar un sólo core siguiendo la idea del buffer, hay 2 opciones. Ambas las había comentado para el AY8912 (para no usar fabgl) con @dcrespo3d hace mucho tiempo (lo dejé pochar), juraría que cuando la mejora del dump de video, pero que comento para la gente que nunca ha oido de ello:

- Usar el ULP (Ultra Low Power coprocessor). Paralelización hardware total.
- Usar interrupción timer scanline VGA (estilo uzebox PWM en PAL TV)

La más fácil, casi inmediata de portar como lo estáis haciendo con el segundo core, es el uso del ULP, parecido a la solución de bitluni:

https://github.com/bitluni/ULPSoundESP32

Bitluni usa acceso RTC_SLOW_MEM y flash (donde está el sample), así como salida DAC, en lugar de PWM digital, pero el concepto es el mismo. Aquí sólo se usaría el ring buffer en RTC_SLOW_MEM y la salida a pin digital si deja, sino al DAC en analógico.

El ULP está incluido en cualquier ESP32, tanto con un sólo core, como con 2. Es el que garantiza la norma de bajo consumo y despierta al resto de core's y módulos del ESP32. Tiene varias particularidades, como que sólo puede acceder a determinados módulos, registros y parte de SRAM, en concreto sólo a la RTC_SLOW_MEM (8 KB), que para ring buffer, como sería de 2048 bytes o 256 bytes en modo bit empaquetado, es decir, se tiene de sobra. La RTC_SLOW_MEM se comparte con más módulos, como el WIFI.

La segunda opción de usar la interrupción de generación de video ya no es tan inmediata. A la hora de rellenar el ring buffer, se requeriría una función de ajuste VGA y PWM states. Cada modo de video vga difiere el número de scanlines. Pero la rutina de ring buffer a reproducir sería tan simple como una escritura a pin en cada comienzo de scanline (hsync), antes del envio de datos por DMA, o después.

Avatar de Usuario
dcrespo3d
Mensajes: 132
Registrado: 04 Nov 2020 08:51
Agradecido : 115 veces
Agradecimiento recibido: 149 veces

Re: Estreno nuevo subforo y avances emulador Spectrum dcrespo

Mensajepor dcrespo3d » 19 Jun 2022 18:20

Eremus escribió:He subido el experimento a mi repo en una nueva rama llamada audio-test: https://github.com/EremusOne/ZX-ESPectr ... audio-test


Hola, ya lo he probado. Tu versión no tiene microcortes y suena más limpio. Pero las frecuencias son incorrectas, los tonos suenan más graves de lo que deben (he activado el SHOW_FPS y va por debajo de 50, depende del juego, pero alrededor de 47fps). En mi versión los tonos suenan a su frecuencia, pero tienen microcortes y suenan más sucios (aunque vaya a 50fps).

Lo ideal sería quedarse con lo mejor de las dos versiones -grin
DavidPrograma en YouTube, GitHub

Avatar de Usuario
Eremus
Mensajes: 42
Registrado: 01 May 2022 18:10
Agradecido : 67 veces
Agradecimiento recibido: 73 veces

Re: Estreno nuevo subforo y avances emulador Spectrum dcrespo

Mensajepor Eremus » 19 Jun 2022 22:30

Hola de nuevo -grin

dcrespo3d escribió:
Eremus escribió:He subido el experimento a mi repo en una nueva rama llamada audio-test: https://github.com/EremusOne/ZX-ESPectr ... audio-test


Hola, ya lo he probado. Tu versión no tiene microcortes y suena más limpio. Pero las frecuencias son incorrectas, los tonos suenan más graves de lo que deben (he activado el SHOW_FPS y va por debajo de 50, depende del juego, pero alrededor de 47fps).

En mi prueba de concepto es normal que el sonido suene mas limpio. Siguiendo el enfoque del articulo del Yass que puse, decidí usar el DAC de 8 bits que tiene la ESP32 además de aplicarle el procesado 8-tap que lo "suaviza". Luego, la toma de muestras se realiza de manera homogénea (cada 73 tstates, lo que da aprox. una frecuencia de muestreo de 48khz) y con eso (salen 957 muestras por frame, 47850 Hz) se rellena el buffer.

Código: Seleccionar todo

    audioCnt += statestoadd; // Cuenta de tstates para toma de muestra de audio

    if (audioCnt >= 73) { // aproximadamente 69888 tstates divididos entre 960 muestras (960 -> 48000hz / 50hz)

   // Todo esto está inspirado en como lo hace el Yass:
        signal = (Ports::base[0x20] & 0x10) ? 255 : 0; // Audio speaker
        signal += (CPU::tapeaudio) ? 191 : 0; // Audio tape
        // Now, add audio output over an 8 tap filter:
        // 1: Maintain 7/8ths of the original signal
        audioOutput -= (audioOutput / 8);
        // 2: ...and add 1/8th of the new one
        audioOutput += (signal / 8);
       audioOutput = signal;

    // Muestra lista: enviar al buffer
        ESPectrum::audioBuffer[ESPectrum::audioBufferHead] = audioOutput;
        ESPectrum::audioBufferHead++;
        if (ESPectrum::audioBufferHead==AUDIO_BUF_SIZE) ESPectrum::audioBufferHead=0;

   // Ajustar el contador de tstates
        audioCnt -= 73;

    }

En tu prueba, parece que capturas el bit de audio después de cada instrucción y rellenas el intervalo de tstates en el buffer con el valor del bit de audio. Creo que el enfoque "Yassiano" de capturar la muestra real cada X tiempo es mas correcta pero probablemente genere mas carga al estar comprobando el tstate todo el rato. Además, la calidad de sonido de tu enfoque sera similar o igual al mio si lo pasamos a modo DAC analógico y le metemos el mismo procesado que en mi prueba. Ambos enfoques nos pueden servir pienso yo. Donde vamos a tener problema es en la segunda parte: reproducir el buffer a la frecuencia mas parecida a la de la toma de muestras (47850 Hz).

A priori la cosa es simple: un loop en el otro core que va volcando el buffer al DAC con las pausas necesarias para hacerlo a la frecuencia deseada. Pero tiene sus problemas: por lo que he podido comprobar, la función delaymicros() parece que no pone en espera al procesador, mas bien ejecuta NOPS durante el periodo necesario. Eso parece que genera carga al tasker de RTOS y, de rebote, impacto en el rendimiento general. Por otra parte, las instrucciones del loop que va mandando el buffer al DAC, consumen su tiempo así que hay que descontarlo del delay. Sin instrumentos de medición (ni talento para usarlos -grin) por ahora voy a ojímetro. En mis pruebas, active F2 y F3 para jugar con el delay. Si lo pruebas veras como puedes corregir la frecuencia de los tonos pero, probablemente, aparezcan los microcortes en algún momento.

Lo que ya voy teniendo claro es que, si queremos que la cosa suene bien y no haya microcortes, el loop de cpu tiene que estar supeditado a la generación de audio: el audio tiene que ser la fuente de la sincronización. Cada buffer de audio se tiene que reproducir en 20 milisegundos si o si, después generar un frame y esperar a que el buffer de audio termine para repetir lo mismo ad-infinitum.

Lo siguiente que voy a probar es usar la solución de Bitluni de reproducir mediante el ULP (gracias @ackerman! -grin). Sabemos producir una muestra de audio a una frecuencia dada así que solo hay que alimentar al ULP y si lo he entendido bien y el ULP va a su rollo, no debería marear ni a nuestra maintask ni al tasker de RTOS con lo que la cosa puede quedar bien.

Como eso nos quede bien, me pongo a probar llevar la generación de video al otro core. Ahora que entiendo mejor la sincronización entre tareas, quiza consiga mantener bien sincronizada la generación de video y tener multicolor y efectos de borde en dual core.

Sonido en ULP, procesador en core 1 y video en core 0 y a vivir la vida! -thumbup

Avatar de Usuario
dcrespo3d
Mensajes: 132
Registrado: 04 Nov 2020 08:51
Agradecido : 115 veces
Agradecimiento recibido: 149 veces

Re: Estreno nuevo subforo y avances emulador Spectrum dcrespo

Mensajepor dcrespo3d » 20 Jun 2022 13:05

Eremus escribió:Lo que ya voy teniendo claro es que, si queremos que la cosa suene bien y no haya microcortes, el loop de cpu tiene que estar supeditado a la generación de audio: el audio tiene que ser la fuente de la sincronización. Cada buffer de audio se tiene que reproducir en 20 milisegundos si o si, después generar un frame y esperar a que el buffer de audio termine para repetir lo mismo ad-infinitum.

[...]

Sonido en ULP, procesador en core 1 y video en core 0 y a vivir la vida! -thumbup


Parece que lo tienes mucho más claro que yo, sigue explorando ese camino. Sólo me puse a mirarlo porque ví que en tu lista de prioridades esto del sonido lo tenías lo último -grin

No tiene sentido que estemos los dos trabajando en lo mismo en paralelo, y me da la impresión de que lo tienes bastante más avanzado. Mientras el vídeo vaya a 50Hz y el sonido siga limpio como ahora, y los tonos suenen a la frecuencia correcta, el emulador irá por el buen camino -thumbup
DavidPrograma en YouTube, GitHub

Avatar de Usuario
zx81
Mensajes: 469
Registrado: 23 Feb 2013 21:31
Agradecido : 86 veces
Agradecimiento recibido: 223 veces

Re: Estreno nuevo subforo y avances emulador Spectrum dcrespo

Mensajepor zx81 » 20 Jun 2022 22:18

El sonido, el puñetero sonido... el tema da como para escribir un libro y/o cortarse las venas.

Lo que veo ahí no me hace presagiar nada bueno. Siento ser tan claro y directo, pero es lo que pienso. A riesgo de acabar en "tocho inside", haré las siguientes consideraciones:

1.- Una frecuencia de 48 kHz parece muy chachi, pero es innecesaria. Serviría, en principio, para poder reproducir señales de hasta 24 kHz, 2000 Hz por encima del rango audible modelo "lush life", que casi nadie tiene. El beeper del Spectrum fijo que no llegaba muy por encima de 8 Khz, y posiblemente ni eso. O sea, con una frecuencia de 32 kHz se va más que sobrado.

2.- Una cosa muy puñetera del sonido es que se deben generar la cantidad de muestras necesaria, ni muchas, ni pocas. Eso de calcular a ojímetro un sample cada 73 t-states, produce una frecuencia de sampleo de 47.945,2 Hz. Mal asunto ese. Ya de por sí, es casi imposible cuadrar un número de muestras exactas por frame aunque, en el peor de los casos, al menos cuadrará una vez por segundo, o debería. Y si no cuadra, se oye, os aseguro que se oye, o más bien se sufre. Nada de descartar cachitos, por pequeños que sean. 47945,2 / 50 = 958,904 samples por cuadro y lo que hay detrás de la coma no se puede descartar, que es casi un sample completo. Ese "if (audioCnt >= 73)" me pone los pelos de picos pardos.

3.- Para usar menos CPU, se puede hacer al contrario, contar los ciclos transcurridos entre dos cambios del bit de beeper (falso, también es necesario el bit de mic, pero por simplificar) y generar un número de muestras proporcional a los ciclos pasados entre cambios. Salvo voces polifónicas, muchas melodías dejan pasar cientos de t-states entre cambios de estado del bit del beeper. Vuelvo a insistir vehementemente en que no es posible de ningún modo descartar o añadir nada, porque luego se escucha todo. Lo "mejor" es cuando empieza a producirse aliasing, la cacofonía puede llegar a ser indescriptible.

4.- Cuantos más filtros pongas, da igual que sean filtros FIR o IIR, menos suena a Spectrum. El sonido del ordenador es sucio, de un sucio imposible de replicar ni siquiera por un SID de C64, ya quisieran, ya. Determinadas melodías tienen armónicos en el original, y no vale comprobar contra otro emulador, hay que escuchar el original para hacerse una idea real de lo que se debería oír. Por experiencia sé que emular a otro emulador, no es buena idea.

Lo de las pesadillas para cuadrar los samples generados por el beeper, con los generados por el AY, lo dejo para otro día.
Cuando utilizo una palabra, esa palabra significa, exactamente, lo que yo quiero que signifique. Ni más, ni menos.
Humpty Dumpty

Empieza a jugar sin tener que compilar: Emulador JSpeccy
ZX Spectrum bare-metal para Raspberry PI ZXBaremulator


Volver a “Desarrollo emuladores ESP32”

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 1 invitado