Seuls les membres ayant 30 points peuvent parler sur le chat.

Forum Casio - Projets de programmation


Index du Forum » Projets de programmation » gint : un noyau pour développer des add-ins
LephenixnoirHors ligneAdministrateurPoints: 15483 Défis: 136 Message

gint : un noyau pour développer des add-ins

Posté le 20/02/2015 17:30

Les SDKs classiques pour écrire des add-ins sont le fx-9860G SDK de Casio avec fxlib (pour Graph monochrome) et le PrizmSDK avec libfxcg (pour Prizm et Graph 90+E). Voici mon alternative : le fxSDK avec gint, pour toutes les plateformes.

Contrairement à fxlib et libfxcg, qui appellent les fonctions de l'OS pour faire leur travail, gint est un noyau indépendant de l'OS qui exploite seul le matériel et le met à disposition de votre add-in. Il vous offre plus de finesse sur le contrôle du matériel, notamment le clavier, l'écran et les horloges, de meilleurs performances sur le dessin, les drivers et la gestion de interruptions, et des choses entièrement nouvelles comme le moteur de gris.

Toutes les sources de gint sont publiques et accessibles sur la forge de Planète Casio :

» Dépôt Gitea Lephenixnoir/gint «

Voici plus précisément ce que gint vous offre de nouveau :

• Un contrôle détaillé du clavier pour les jeux, parfait pour les combos !
• Des timers avec une précision de 60 ns, d'autres à 30 µs
• Toutes vos images converties automatiquement sans code à copier (plus de Sprite Coder)
• Des polices personnalisées
• Des fonctions de dessin, d'images et de texte fulgurantes et optimisées la main
• Mesurer les performance de votre code à la microseconde près (avec libprof)
• Le contrôle du matériel et des interruptions
• Plein de petites choses pratiques comme dprint(1, 1, "x=%d", x)

• (Graph monochrome) Un moteur de gris pour faire des jeux en 4 couleurs !
• (Graph monochrome) La compatibilité SH3 et SH4, avec le même fichier g1a.

• (Graph 90+E) Une nouvelle police de texte, plus lisible et économe en espace
• (Graph 90+E) Le dessin en plein écran, sans les bordures blanches et la barre de statut !
• (Graph 90+E) Un driver écran capable de triple-buffering

Le coût de tout ceci, c'est que vous avez une copie du code de gint dans votre add-in. Cela prend environ 20 ko de place (selon la quantité de fonctions que vous utilisez), soit à peu près comme le sprintf() de fxlib qui fait 18 ko !

Et voici quelques photos et captures d'écran !





Tester gint sur votre machine

La fin du portage vers la Graph 90+E signera la sortie de gint v2. L'add-in de test de l'application est désormais gintctl :

» Dépôt Gitea Lephenixnoir/gintctl «

En plus de tester les fonctionnalités de gint, cet add-in contient quelques outils permettant d'inspecter la machine, la mémoire, et les registres. Je le développe au fur et à mesure, et je posterai un protocole de test complet avec la sortie de la v2 !

Utiliser gint pour développer des add-ins

Normalement, vous avez besoin du fxSDK pour développer avec gint. Le fxSDK est compatible avec Linux et Mac OS, et on peut réfléchir à un portage sous Windows s'il y a vraiment des intéressés. Il faut l'installer en premier (et avoir un cross-compilateur GCC).

La procédure de compilation et d'installation de gint est décrite sur le README du dépôt, c'est du configure - make tout à fait banal.

Une fois que gint est installé sur votre système, voyez les tutoriels de développement pour avoir un aperçu de son fonctionnement. La plupart des choses sont expliquées dans les en-têtes (fichiers .h) de la bibliothèque que vous pouvez consulter en ligne, sur votre copie locale du dépôt, ou dans les dossiers d'installation du compilateur.

Obtenir la dernière version de gint après une mise à jour

Je pousse régulièrement des mises à jour de gint sur le dépôt du projet. Pour les télécharger, tapez git pull, puis recompilez et réinstallez gint avec make et make install.


Fichier joint


Pages : Précédente1 ... , 20, 21, 22, 23, 24, 25
LephenixnoirHors ligneAdministrateurPoints: 15483 Défis: 136 Message

Citer : Posté le 08/09/2019 17:38 | #


Excellent ! Tout devrait tomber en place rapidement.
Max1trucHors ligneMembrePoints: 17 Défis: 0 Message

Citer : Posté le 08/09/2019 17:59 | #


En fait, je rencontre un nouveau problème, en incluant respectivement les dossiers include et lib avec -I et -L.
$ fxsdk build-fx

:: Making into build-fx

sh4eb-nofpu-elf-gcc -o build-fx/src/Piles.elf build-fx/src/main.o  -mb -ffreestanding -nostdlib -Wall -Wextra -fstrict-volatile-bitfields -std=c11 -Os -I/home/user/Documents/src/casio/include -L/home/user/Documents/src/casio/lib -m4-nofpu -DFX9860G -Tfx9860g.ld -lgint-fx  -lgcc -Wl,-Map=build-fx/map
/home/user/Documents/src/casio/lib/gcc/sh4eb-nofpu-elf/8.3.0/../../../../sh4eb-nofpu-elf/bin/ld: cannot open linker script file fx9860g.ld: No such file or directory
collect2: error: ld returned 1 exit status
Makefile:73: recipe for target 'Test.g1a' failed
make: *** [Test.g1a] Error 1

Visiblement il ne trouve pas le fichier fx9860g.ld

EDIT: "fx9860g.ld" est dans le dossier bin de mon préfix custom, le même dossier que "libgint-fx.a"

Ajouté le 08/09/2019 à 18:06 :
En fait, c'est bon il suffisait d'utiliser le dossier "bin" au lieu du dossier "lib" pour l'option "-L"
Niveau de curiosité:
   99%
LephenixnoirHors ligneAdministrateurPoints: 15483 Défis: 136 Message

Citer : Posté le 08/09/2019 18:06 | #


Ah, intéressant ! Il faut visiblement spécifier explicitement -L au linker pour ajouter un répertoire personnalisé à la recherche du linker script. Essaie avec -Xlinker -L -Xlinker <folder> en plus.

Edit : Okay, tant mieux !
Max1trucHors ligneMembrePoints: 17 Défis: 0 Message

Citer : Posté le 08/09/2019 21:37 | #


Une petite question, comment puis-je faire des syscalls avec fxsdk, gint et gcc? La méthode pour le SDK casio ne fonctionne pas...
Niveau de curiosité:
   99%
LephenixnoirHors ligneAdministrateurPoints: 15483 Défis: 136 Message

Citer : Posté le 08/09/2019 21:56 | #


On les fait proprement en assembleur. La méthode utilisée en C avec le SDK est une aberration...

Il y a plein d'exemples ici : https://gitea.planet-casio.com/Lephenixnoir/gint/src/branch/compat/src/core/syscalls.S

Fais gaffe à ce que tu appelles ; s'il y a un équivalent gint alors il faut définitivement utiliser cet équivalent. Si tu arrives ou n'arrives pas à utiliser des syscalls, je veux bien savoir ; les limites de ce qui est compatible sont encore floues.
Max1trucHors ligneMembrePoints: 17 Défis: 0 Message

Citer : Posté le 08/09/2019 22:10 | #


En fait j'ai créé un fichier "syscalls.S" avec ce code:
.global _battery

.section ".pretext"

#define syscall(id)                     \
        mov.l   syscall_table, r2       ;\
        mov.l   1f, r0                  ;\
        jmp     @r2                     ;\
        nop                             ;\
1:      .long   id

_battery:
        syscall(0x39C)

Mais à la compilation il ne trouve pas le fichier en assembleur.
Niveau de curiosité:
   99%
LephenixnoirHors ligneAdministrateurPoints: 15483 Défis: 136 Message

Citer : Posté le 08/09/2019 22:18 | #


Ah, mais c'est que j'ai pas mis les règles assembleur. Fiouh...

J'ai poussé sur le dépôt du fxSDK une nouvelle version du Makefile avec les règles appropriées. Pour l'utiliser, il suffit normalement (mais pas pour toi) de pull le dépôt et réinstaller le fxSDK, puis taper fxsdk update dans le dossier de ton projet.

Sauf que tu as modifié le Makefile, et la dernière commande l'écraserait. Tu veux certainement pas repartir de zéro. Tu peux faire la dernière étape à la main en récupérant les nouvelles règles ici : https://gitea.planet-casio.com/Lephenixnoir/fxsdk/commit/4f145cb202ae7104e12ba2e1f6d49e93dc2e6fa0

Je réalise que mon Makefile n'est pas vraiment flexible, il est issu de celui de gintctl et ne permet pas du tout de changer de toolchain facilement. Il faut que j'en fasse un plus souple.
Max1trucHors ligneMembrePoints: 17 Défis: 0 Message

Citer : Posté le 08/09/2019 22:19 | #


Ok merci !
Niveau de curiosité:
   99%
LephenixnoirHors ligneAdministrateurPoints: 15483 Défis: 136 Message

Citer : Posté le 09/09/2019 09:26 | #


Max1Truc a écrit :
- A la compilation de gint, j'ai dû changer le fichier fxconv.py qui est dans le PATH en modifiant la déclaration de la fonction "elf" en ligne 673:
def elf(data, output, symbol, section=None, arch="sh4"):

Voilà, j'ai poussé sur le dépot du fxSDK un nouveau commit introduisant les options appropriées pour fxconv :

--toolchain pour spécifier la toolchain à utiliser (eg. sh3eb-elf)
--arch pour spécifier l'architecture cible (eg. sh3 ou sh4-nofpu)
--section pour spécifier la section cible (eg. .rodata)

Ça devrait résoudre ton problème de façon plus élégante.

Ajouté le 13/09/2019 à 08:21 :
Encore une modification importante aujourd'hui !

Après avoir ajouté les gestionnaires d'exceptions (les System ERROR si vous voulez), on m'a suggéré de permettre au programmeur d'afficher les infos qu'il voulait. J'ai donc ajouté une fonction gint_panic_set() que l'on peut appeler pour choisir sa propre fonction pour debugger en cas d'erreur. Typiquement vous voudrez afficher plein d'infos à l'écran... voire scroller avec getkey().

(Détail technique : l'ancien panic tournait dans le gestionnaire d'exceptions, et ne pouvait donc pas utiliser d'interruptions. Donc pas de getkey(), pas de sleep(), plein de trucs limitants. Désormais je rte directement dans le panic, ce qui signifie que le panic peut utiliser toutes les fonctions. Techniquement parlant c'est une bonne avancée !)

En plus de ça, j'ai ajouté un mécanisme permettant de rattraper les exceptions. J'en ai besoin pour mon inspecteur de mémoire dans gintctl. En effet, dès qu'on se met sur une adresse invalide, ça fait une TLB error et l'add-in plante. Ce mécanisme permet d'être informé que l'erreur s'est produite et de continuer quand même l'exécution. Ainsi, l'add-in reprend, réalise qu'il a été informé d'une erreur, et affiche "TLB error" à toutes les adresses invalides.
MilangHors ligneMembrePoints: 284 Défis: 0 Message

Citer : Posté le 13/09/2019 11:29 | #


Lephenixnoir a écrit :

En plus de ça, j'ai ajouté un mécanisme permettant de rattraper les exceptions. J'en ai besoin pour mon inspecteur de mémoire dans gintctl. En effet, dès qu'on se met sur une adresse invalide, ça fait une TLB error et l'add-in plante. Ce mécanisme permet d'être informé que l'erreur s'est produite et de continuer quand même l'exécution. Ainsi, l'add-in reprend, réalise qu'il a été informé d'une erreur, et affiche "TLB error" à toutes les adresses invalides.


Rattraper des exceptions ?
Mais, c'est à dire que à terme, même après une exception un addin pourra continuer à s'exécuter ? Mais c'est fantastique ça

Par contre, sinon, j'ai toujours quelques problèmes autour du DMA, lorsque je lance DMA memset, ma calculatrice freeze (G 35 ++ 2.05.2201 donc bien sh4)
Une alternative intéressante à toutes les boucles que vous avez vu jusque là :
For 1→X To 2:X-1→X:Next :E

Projet de jeu multijoueur : 1V1 3D
LephenixnoirHors ligneAdministrateurPoints: 15483 Défis: 136 Message

Citer : Posté le 13/09/2019 11:32 | #


Milang a écrit :
Mais, c'est à dire que à terme, même après une exception un addin pourra continuer à s'exécuter ? Mais c'est fantastique ça

Ben, pas vraiment. Si l'add-in fait un accès mémoire illégal et qu'on continue l'exécution, le registre de destination contiendra une valeur complètement arbitraire. Ça ne marche que si l'add-in prévoit que l'accès peut échouer et le détecte. C'est donc très marginal.

Par contre, sinon, j'ai toujours quelques problèmes autour du DMA, lorsque je lance DMA memset, ma calculatrice freeze (G 35 ++ 2.05.2201 donc bien sh4)

Fichtre, va falloir que je regarde tout ça en détail.

Ajouté le 14/09/2019 à 10:12 :
Milang a écrit :
Par contre, sinon, j'ai toujours quelques problèmes autour du DMA, lorsque je lance DMA memset, ma calculatrice freeze (G 35 ++ 2.05.2201 donc bien sh4)

Je peux reproduire sur ma Graph 75+E en 02.05.2201, je vais enquêter.

Ajouté le 14/09/2019 à 16:21 :
J'ai implémenté un outil de visualisation pour le DMA dans gintctl, et le freeze se produit dès que j'utilise un transfert sans interruptions. Par ailleurs j'ai du mal à lire/écrire correctement dans les registres du DMA.

Ajouté le 14/09/2019 à 17:36 :
Tous les registres sont à 0, je commence à me demander s'il y a un DMA. Ce qui expliquerait pourquoi ça freeze en mode sans interruption vu qu'il attend immédiatement explicitement la fin du transfert qui de toute façon n'existe pas.
MilangHors ligneMembrePoints: 284 Défis: 0 Message

Citer : Posté le 14/09/2019 18:28 | #


Peut être que les adresses du dma ne sont pas les mêmes
Une alternative intéressante à toutes les boucles que vous avez vu jusque là :
For 1→X To 2:X-1→X:Next :E

Projet de jeu multijoueur : 1V1 3D
LephenixnoirHors ligneAdministrateurPoints: 15483 Défis: 136 Message

Citer : Posté le 14/09/2019 18:31 | #


J'ai tenté toutes les adresses connues de modules DMA de SimLo sans succès.

Ce serait la première différence majeure découverte entre les SH7305 qui équipent les Graph mono et les Graph 90+E.

D'un côté, la doc de SimLo ne concerne que des SH3 et la Prizm. Or, la Prizm a définitivement besoin d'un DMA sinon l'écran ne tient pas la performance. Il n'est pas impossible que Casio ait éliminé le DMA du design des Graph mono pour économiser.

J'ai en tête une idée pour détecter expérimentalement les registres dans l'espace d'adressage, mais c'est tordu et ça pourrait être dangereux sur les bords. Pour l'instant je ne vois pas où aller d'autre.

Ajouté le 15/09/2019 à 12:29 :
J'ai continué d'enquêter avec le DMA sur Graph 90.

Jusqu'ici je n'arrive pas à exécuter dma_memcpy() proprement, le transfert se conclut sans erreur mais les données à l'arrivée sont fausses. De plus, on ne gagne quasiment rien.

Pour vous donner une idée, afficher une image en R5G6B5 (le format le plus rapide à afficher mais le moins compact) prend 24.7 ms en processeur pur, et le transfert équivalent (mais qui produit des mauvaises données pour l'instant) prend 21.3 ms. En montant l'overclock au maximum, ces temps descendent à 16.5 ms et 14.8 ms.

C'est assez décevant. J'aimerais comprendre plus finement les relations entre les fréquences des différentes mémoires présentes, et tenter d'exploiter des techniques un peu plus tordues pour l'accélérer. 40 FPS avec triple-buffering juste pour une image en plein écran, c'est vraiment pas extraordinaire.

Pour référence, je pense actuellement à utiliser les mémoires IL (4k), X (8k) et Y (8k) qui sont des bouts de mémoire normalement plus rapides que la RAM. Ça peut pas faire des miracles car il y a 170k de VRAM en tout. Mais on peut s'en servir pour le code très chaud en calcul, et j'envisage de m'en servir pour des données graphiques lorsque le rendu est compliqué (eg. alpha blending). Je ne sais pas à quel point on va gagner toutefois, parce qu'il y a déjà le cache dans la partie, et il est possiblement encore plus rapide...

J'ai en tête un certain type d'affichage de jeu (à trois lettres, cough cough) que j'aimerais pouvoir faire à une fréquence raisonnable. Notamment un HUD, une map tilée en plein écran avec possiblement deux calques, des entités sur la map et quelques effets spéciaux possiblement avec alpha blending. Pour l'instant les performances ne permettent pas de jouer à ça.

Ajouté le 15/09/2019 à 14:48 :
J'ai mis le doigt sur les deux défauts de comportement qui me restaient encore à éclairer.

D'abord, le fait que les données soient invalides quand j'exécute un dma_memcpy(). Avec tous les transferts de VRAM que j'ai faits, j'ai fini par oublier que les images sont dans la ROM et virtualisées dans l'espace d'adressage. Or le DMA utilise des adresses physiques, ce qui pose un énorme problème. Il est facile de trouver l'adresse physique qui est virtualisée à chaque endroit de l'espace d'adressage, mais les données virtualisées ne sont pas continues dans la mémoire physique.

Autrement dit, à cause de la fragmentation du système de fichiers, il est impossible d'afficher de façon générale des images prises dans la ROM avec le DMA. Et si les images tiennent dans la RAM alors elles sont assez petites pour que ça ne vale pas la peine d'utiliser le DMA.

Ensuite, le fait que j'aie des freezes et des différences de comportement quand ma source est la mémoire IL. J'ai fini par mettre la main dessus dans la doc :

10.5.4 - Sleep Mode
The SuperHyway bus master module, such as DMAC, cannot access IL memory in sleep mode.

Pris autrement, cela signifie qu'on ne peut pas endormir le processeur pendant un transfert DMA dont la source ou la destination est la mémoire IL. Ce n'est pas un problème en soi. Seulement, lors de mes tests j'attendais toujours que le transfert DMA se termine avant de rendre la main au programme pour éviter des effets tordus. Lorsque les interruptions sont activées, mon driver effectue cette attente en endormissant la calculatrice, ce qui arrête aussi la mémoire IL, et donc le transfert DMA, et donc la calculatrice ne se réveille jamais.

Avec ça, mon driver contient maintenant toutes les fonctions que j'envisageais initialement, il n'y a plus aucun bug connu, et je peux même accéder à la mémoire IL. Par contre le gain de performance est très modeste, et loin d'être satisfaisant.
Dark stormEn ligneMembre d'honneurPoints: 10820 Défis: 176 Message

Citer : Posté le 15/09/2019 19:02 | #


Seulement, lors de mes tests j'attendais toujours que le transfert DMA se termine avant de rendre la main au programme pour éviter des effets tordus.


Dans le cas d'un affichage de VRAM, les cas tordus dont tu parles ce sont des read/write after read/write ? Dans ce cas, le seul problème qui peut avoir lieu, c'est que quelques octets de la VRAM soient corrompus, et dans ce cas on a quelques pixel qui sont pas de la bonne couleur, pour une frame uniquement.

L'intérêt que je vois du DMA, c'est justement de pouvoir paralléliser le calcul physique et de rendu avec le transfert de la VRAM. Si on attend que le DMA ait fini sa copie, je vois moins l'intérêt.

Et avec un système de flag/lock, y'a pas moyen de paralléliser ce qui est possible, puis ensuite attendre que le DMA ai fini pour relancer une copie ? Ou alors j'ai pas tout à fait compris que ce tu faisais…
Finir est souvent bien plus difficile que commencer. — Jack Beauregard
Páranÿe quetë Quendya
LephenixnoirHors ligneAdministrateurPoints: 15483 Défis: 136 Message

Citer : Posté le 15/09/2019 19:09 | #


En effet, pour l'instant je me place dans un cadre où corrompre une partie de la VRAM n'est pas acceptable. En plus, continuer l'exécution pendant que le DMA tourne peut donner des surprises très déplaisantes comme freezer n'importe comment si tu réutilises le DMA avant que le transfert ne soit fini. Mon application de test en serait capable...

Ici, il ne s'agit pas d'utiliser le DMA pour faire le transfert à l'écran (qui marche déjà tout seul) mais carrément pour dessiner ou transférer de la mémoire. Dans ce cas, l'intérêt était que l'opération était plus rapide. Je ne parle même pas encore de paralléliser. (En effet, dans le cas VRAM → DD, paralléliser est facile car il suffit de changer de VRAM. Mais dans le cas dessin c'est moins évident.)

En tous cas, oui on peut sans problème bosser un moment selon les possibilités plus attendre le DMA plus tard. Il suffit d'appeler dma_transfer(), bosser, puis appeler dma_transfer_wait(). Actuellement je fais les deux d'un coup parce que mon add-in de test s'en fout royalement, il a déjà des perfs très larges.
LephenixnoirHors ligneAdministrateurPoints: 15483 Défis: 136 Message

Citer : Posté le 15/09/2019 19:35 | # | Fichier joint


Je viens de pousser une série de commits qui ajoute dma_memcpy() et trois macros GILRAM, GXRAM et GYRAM qui permettent de placer des données dans les trois mémoires on-chip de la calculatrice, les mémoires IL, X et Y.

J'ai également construit une expérience dans gintctl permettant de mesurer la taille de ces zones ; elles font 4k, 8k et 8k respectivement.

MilangHors ligneMembrePoints: 284 Défis: 0 Message

Citer : Posté le 15/09/2019 20:25 | #


Du coup, il y a finalement un dma sur les graph monochromes ou non ?
Une alternative intéressante à toutes les boucles que vous avez vu jusque là :
For 1→X To 2:X-1→X:Next :E

Projet de jeu multijoueur : 1V1 3D
LephenixnoirHors ligneAdministrateurPoints: 15483 Défis: 136 Message

Citer : Posté le 15/09/2019 21:33 | #


Milang a écrit :
Du coup, il y a finalement un dma sur les graph monochromes ou non ?

Pour l'instant non, il n'y en a pas.
Pages : Précédente1 ... , 20, 21, 22, 23, 24, 25

Planète Casio v42 © créé par Neuronix et Muelsaco 2004 - 2019 | Il y a 50 connectés | Nous contacter | Qui sommes-nous ? | Licences et remerciements

Planète Casio est un site communautaire non affilié à Casio. Toute reproduction de Planète Casio, même partielle, est interdite.
Les programmes et autres publications présentes sur Planète Casio restent la propriété de leurs auteurs et peuvent être soumis à des licences ou copyrights.
CASIO est une marque déposée par CASIO Computer Co., Ltd