Vers un G90 Compatibility Tool ?
Posté le 24/04/2018 00:45
Comme vous l'avez sûrement vu évoqué si vous avez un peu suivi ce qu'il s'est passé ces derniers mois, la nouvelle Graph90 de Casio supporte très bien le développement de programmes natifs (toujours de manière aussi «non-officielle» que pour son ancètre la fx-CG20), en atteste par exemple l'émulateur de Gameboy
Prizoop développé par tswilliamson. De plus celle-ci est hautement compatible avec la fx-CG20, ce qui lui permet potentiellement d'avoir une bibliothèque de jeux assez large. Cependant pour qu'un addin développé pour fx-CG20 soit nativement compatible avec la G90, plus récente, il faut que l'addin ait été écrit relativement proprement, notamment en n'hardcodant pas certaines adresses mais en les utilisant de manière dynamique via les syscalls disponibles, et à ce jour assez bien documentés…
Et donc malgré cette assez grande compatibilité, au lancement de la machine, un peu à la manière de ce qui est arrivé lors du
lancement des SH4 chez les G*5, nombre d'addins fonctionnant sur fx-CG20 ne fonctionnaient pas sur G90. Une liste globalement à jour de la situation actuelle est dispo sur TiP
ici.
Le problème majeur qui a été identifié est la pratique consistant à coder en dur l'adresse de la mémoire vidéo dans la plupart des routines graphiques, conduisant à l'absence pure et simple de graphismes pour certains addins lorsque lancés sur G90, l'adresse de la VRAM étant passé de
0xA8000000 sur fx-CG20 à
a priori 0xAC000000 sur G90. C'est ce qu'on retrouve sur une grosse partie des fonctions de ce
topic qui faisait pas mal référence au début, ColorLib de Lancelot utilise ça également, etc, soit une pratique plus que répendue. Quelqu'un qui voudrait coder «proprement» aujourd'hui n'aurait pas vraiment à se poser de telles questions puisqu'on a à notre disposition le syscall
GetVRAMAddress qui dynamise ça sans soucis et fonctionne sur tous les modèles. Mais le fait est que, si on dispose du code source d'un certain nombre de programme et peut donc espérer à terme, en s'y plongeant un peu, les corriger sans trop de heurts, comme ça a déjà été fait par exemple avec
GravityDuck qui avait quelques soucis de cet ordre, pour certains programmes, on ne dispose que du fichier binaire en
.g3a, et le problème s'avère un peu plus délicat à attaquer. (En passant c'est encore un exemple qui montre aux personnes qui n'en seraient toujours pas convaincues que publier ses sources fait rarement du mal à un programme…
)
L'idée est donc de voir si on peut arriver à s'approcher de quelque chose qui ressemblerait au
SH4CT de Ziqumu.
Naïvement pour tester ce que ça donnait, j'avais dans un premier temps essayé de simplement remplacer les occurences de
0xA8000000 par
0xAC000000 dans le binaire, corriger le checksum et envoyer sur G90 avec des addins réputés ne marchant pas, et rien de bien probant : entre le SystemError et l'absence d'amélioration globalement.
En ayant un peu discuté avec LePhenixNoir, ça risque d'être un peu délicat à gérer, entre les occurences de
A8000000 qui peuvent n'avoir rien à voir avec la VRAM, et les optimisations du compilateur qui font qu'il faut modifier plus que l'adresse…
Pour commencer moins ambicieux, je pensais déjà essayer de trouver des moyens systématiques d'arriver à faire la conversion sur des programmes simples, dont on a le contrôle des sources notamment. Et il s'avère que si pour un programme du type :
#include <fxcg/keyboard.h>
void square()
{
short *vram = (short*)0xA8000000;
//short *vram = (short*)0xAC000000;
for(int i = 0; i < 5000; i++) {
*vram = 0x001F;
vram++;
}
}
int main()
{
int key;
square();
GetKey(&key);
return 0;
}
On doit pouvoir y arriver assez automatiquement à coup de simple remplacement de l'addresse de la VRAM, le programme à peine plus complexe suivant donne déjà un peu plus de fil à retordre avec les optimisations de GCC activées ("malheureusement" il y a de grandes chances pour que les binaires que l'on a à disposition aient été compilés avec des optimisations de GCC) :
#include <fxcg/keyboard.h>
void square()
{
short *vram = (short*)0xA8000000;
//short *vram = (short*)0xAC000000;
for(int i = 0; i < 50; i++) {
for(int j = 0; j < 50; j++) {
vram[i*384 + j] = 0x001F;
}
}
}
int main()
{
int key;
square();
GetKey(&key);
return 0;
}
En gros GCC profite du fait qu'il ait à sa disposition des constantes codées en dur pour précaculer des «trucs», qui auraient aussi besoin d'être modifiés par un éventuel outil, et que les optimisations rendent un peu obscurs à première vue…
Voilà, je ne sais pas exactement où ça va nous ammener, ni exactement à quel point ça va être attaquable… On verra bien ce que ça donne !
Je pense qu'il faudrait aussi en profiter pour faire explicitement une liste propre des addins dont on n'a pas les sources et qui pourraient être candidats à ce processus ; je ne suis pas sûr qu'il y en ait tant que ça finalement donc ce n'est peut être pas le meilleur endroit où investir du temps, pour l'instant !
Citer : Posté le 24/04/2018 08:01 | #
Je pense qu'il faut tâter de binaires réels pour se faire une idée de la faisabilité.
L'idée c'est que très peu de fonctions graphiques vont avoir hardcodé un 50 dans la taille du rectangle. La plupart des jeux s'en sortent en appelant des fonctions génériques situées dans d'autres fichiers. La nuance est importante.
Pour optimiser les calculs graphiques en précalculant des constants, GCC doit connaître à l'avance les dimensions/positions de ce qu'on dessine. Tant que ces données ne sont présentes que dans d'autres fichiers, l'optimisation n'est pas possible. En c'est en particulier vrai avec les libs qui sont toujours génériques. En plus pour les libs on a les sources, donc on peut éventuellement passer à la main dans l'assembleur pour dire « cette occurrence de 0xa8000000 appartient à ColorLib » et avoir des protocoles spécifiques.
Il est à noter que GCC peut inliner entre différentes unités de compilation, mais seulement si les LTO (Link-Time Optimization) sont activées. Cela requiert l'option de configuration --enable-lto et cette fonctionnalité n'a pas été stable tout de suite (me semble qu'au voisinage de gcc 4/5 ça faisait crasher régulièrement le compilo). Je ne pense pas que les add-ins Prizm auront été compilés avec.
Tout n'est pas perdu donc, mais il faut regarder les vrais binaires pour voir.