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

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.