Enhorabuena a todos. Esto es lo que presta, que se puede compartir todo, y pueden salir cosas muy interesantes.

Yo hice pruebas con multicolor, una era cuando se escribía directamente en posiciones de memoria de video, al vuelo y otra en donde la decodificación de instrucciones de cpu por deteccion de tstates por scanline, juraría. También hice detección de cambio de tiles, y dibujar sólo los que cambiaban. Todo esto fue cuando aun era lento el core de @zx81 (Jose Luis Sanchéz), así que lo dejé pochar ahi, junto con más cosas, y cuando ya tiró a toda velocidad, no las retomé. El multicolor en x86 lo hacia bien, pero claro, en x86, como si se pone uno a dibujar pixel a pixel definiendo un pixel como si fuera un polígono, y a dibujar en plan OpenGL, va todo sobrao, da igual, que se haga todo lento, que los PC's van sobraos.
La idea de un buffer auxiliar de @dcrespo3d, es factible. Puede que valga con sólo un par de scanlines, y no haga falta todo. Mientras que la parte del buffer auxiliar se le de todo masticado, simplificando a simples asignaciones o memcpy de 32 bits, en la parte del bucle de decodificación de CPU, es factible. Tiene que ser máxima velocidad, copiar un scanline a saco.
Lo más rápido que existe es crear un buffer DMA en SRAM con
heap_caps_malloc y MALLOC_CAP_DMA Tiene que ser de este tipo, para garantizar 32 bits y controlado por el módulo de DMA. Esto es lo más rápido, el problema, es si el sistema está muy saturado, que entonces, el DMA pierde la eficiencia. También esta el copiado asíncrono
esp_async_memcpy, pero lo mismo, si está muy saturado, pierde la eficiencia. Recordemos, que las librerias de bitluni y fabgl también estan usando el DMA, así que si no orquestamos todo, puede ser un desastre.
Hay que ir podando cosillas, sobre todo en las que más se ejecuten por unidad de tiempo. El ESP32 no es que el coprocesador sea malo, sino que la gestión hasta ahora del mismo, es muy penosa. Así que salvo que se hagan operaciones flotantes en modo ristra de tropecientos números a saco, mejor evitarlos. Quitar también divisiones, restos y multiplicaciones tanto de enteros, como de flotantes.
Código: Seleccionar todo
inline uint8_t CPU::delayContention(uint32_t currentTstates)
{
...
int modulo = halfpix % 8;
}
Cambiarlo por:
return wait_states[(halfpix & 7)];
Y lo más importante, el ESP32 es como el paso del 486 al Pentium, la caché lo es todo. Los 4 KB de caché, no hacen que vaya al doble o triple de velocidad, sino de 100 a 1000 veces más rápido. Así que hay que hacer que caiga la mayor parte de cosas en la caché. Para ello, hay que usar datos pequeños, direccionamiento e indireccionamiento a memoria, lo que viene siendo arrays o punteros, y evitar la pila (el GOTO es la auténtica salud

).
Los task de multihilo penalizan la caché, dado que hay conmutación de tarea.
Código: Seleccionar todo
inline uint8_t Mem::readbyte(uint16_t addr) {
uint8_t page = addr >> 14;
switch (page) {
case 0:
return rom[romInUse][addr];
case 1:
return ram5[addr - 0x4000];
case 2:
return ram2[addr - 0x8000];
case 3:
return ram[bankLatch][addr - 0xC000];
}
}
El inline aunque en x86 vale para muchas cosas, en ESP32, suele valer para algo mucho más pequeño que el switch, por ejemplo, para una asignación de una variable o dos, el resto no lo suele meter en inline. Esta parte es más rápido meterlo sin switch:
Código: Seleccionar todo
extern "C" inline uint8_t fast_readbyte(uint16_t addr)
{
unsigned char idRomRam = (addr>>14);
if (idRomRam == 0)
{
return (gb_local_cache_rom[rom_in_use][addr]);
}
else
{
return (gb_local_cache_ram[(gb_ptr_IdRomRam[idRomRam])][(addr & 0x3fff)]);
}
Y de está forma, se puede hacer otro podado. Como es una placa TTGO VGA32 v1.4, donde hay más RAM, se puede aplicar el truco de @zx81 (Jose Luis Sanchéz), de evitar el chequeo (if (idRomRam == 0) ) del banco 0, que es usar 16KB de RAM, de forma, que al hacer una lectura, lees del puntero a ROM, y al escribir, escribes a un puntero RAM de 16 KB. De esta forma, nunca se escribe a ROM, y la lectura y escritura es inmediata, a costa de sacrificar 16 KB de RAM. Se hace siempre acceso a array de memoria sin tener que usar el if. Este podado, ya permite meterlo en un #define o inline puro auténtico.
Al ESP32, le encanta el operador ternario
( ?: ).
El RTOS no es un SO, pero si es un planificador de tareas avanzado, digamos que actua como un embudo. La forma que tiene de predecir, es con conteo de lo que ha pasado hasta ahora. Así que si se optimiza demasiado, y la cadencia no es constante, lo que haremos es saturarlo, igual que si tiramos demasiado agua de golpe y paramos en seco. Si se lo damos como tiene que ser, al final, va todo en armonia. Es decir, que en algunos casos hay que hacer justo lo contrario, ralentizar, para garantizar la cadencia constante.
Hay muchos más trucos, pero con esto ya se puede ver por donde tirar.
Esta semana, si saco tiempo, desempolvaré lo que tenía hecho del multicolor, y miro más cosas que puedan venir bien.