Technologie : Un‌ Avertissement Majeur !

Cet article présente un projet⁤ en phase de pré-lancement. Je mettrai à jour le contenu et le⁣ projet, ce qui signifie‌ que ce document n’est⁤ pas figé. Si vous souhaitez suivre les modifications, c’est à vous de le faire.⁢ Je ⁣m’engage simplement⁣ à fournir‌ une‍ liste des changements ⁢en bas ⁤de l’article.

Architecture⁤ de PalmOS : Un Peu d’Histoire

Historique

Avant la version 5.4, ⁣PalmOS stockait toutes les données en RAM sous forme de bases de données. Ces bases de données se divisaient en deux catégories : ‌les bases de données d’enregistrement (comme on pourrait⁣ l’imaginer) et​ les bases de données de ressources (similaires aux⁢ ressources⁢ de MacOS classique). Chaque ‌base de données possédait un type et un identifiant de⁣ créateur, ‍chacun étant un ‌entier de ‍32 bits, généralement constitué⁢ de caractères ⁤ASCII. En‍ règle générale, chaque application créait des bases ⁢de données avec son propre identifiant de créateur. Certains types avaient également une signification particulière, ⁣par exemple,‌ « appl » désignait une⁢ application.

Modules, Bibliothèques, ⁣DALs et Pilotes

L’architecture de‌ PalmOS repose sur divers composants,⁤ notamment⁣ des modules,⁣ des bibliothèques, ⁣des DALs (Data⁤ Abstraction Layers) et des pilotes. Ces éléments interagissent pour permettre aux applications​ de fonctionner ⁤de manière fluide sur le⁤ système d’exploitation.

Vers le Premier Port Non Autorisé de PalmOS

Qu’est-ce qui rend cela si difficile ?

Le portage de PalmOS⁢ sur d’autres plateformes présente de nombreux ‌défis. Les formats de ROM‍ sont⁢ complexes, et il est nécessaire ​de développer un DAL pour faciliter l’interaction avec le matériel. Cela ⁢peut sembler simple, mais la réalité est bien plus⁣ compliquée.

Les Formats de ​ROM

Les formats de ROM sont un véritable casse-tête. Chaque appareil a ses ⁤propres ‍spécificités,‌ ce qui complique le processus de portage. Il ‍est essentiel de comprendre quel⁣ type de ROM est utilisé pour chaque⁣ appareil afin de garantir⁣ la compatibilité.

Écriture‍ d’un DAL Minimal

Créer un DAL minimal est une étape cruciale. Cela permet de simplifier les ‍interactions entre le​ système d’exploitation ⁣et‍ le matériel, mais cela nécessite une compréhension approfondie des‌ deux.

La Difficulté du Dessin

Le dessin sur des appareils PalmOS peut s’avérer ‌complexe. Les limitations matérielles et les spécificités ‍du système d’exploitation rendent cette ‌tâche⁢ ardue.

La Controverse de l’Imitation

L’imitation méticuleuse peut être perçue comme une forme de flatterie, mais elle soulève également des questions éthiques. La frontière entre l’inspiration et⁤ le plagiat est‌ souvent floue dans le domaine de ⁤la technologie.

La Carte SD Virtuelle

L’utilisation d’une carte SD virtuelle est une solution ‍innovante pour contourner certaines limitations des appareils PalmOS. Cela⁢ permet d’étendre les capacités de stockage sans nécessiter de matériel supplémentaire.

Quel ROM Utilisez-vous ?

La question de la ROM utilisée est essentielle. Chaque appareil ⁢a ses propres⁢ caractéristiques, et⁣ il⁣ est crucial de s’assurer que le portage fonctionne correctement sur le ⁢matériel cible.

Alors, C’est‍ Fini ? Ça Fonctionne ?

Une fois toutes ces étapes franchies, il est temps ⁣de tester le portage. ​Cela peut sembler simple, ⁣mais de nombreux problèmes peuvent⁤ survenir à ce stade.

Vers le Premier Appareil PalmOS Pirate

Un Aperçu des Appareils PalmOS ⁣5.x

Les appareils PalmOS‌ 5.x, avec leurs processeurs ARM,⁤ ont marqué une avancée significative dans l’évolution de‌ la technologie mobile. Ces appareils ont ouvert la voie à de nouvelles possibilités, mais ⁤ils présentent également des défis uniques.

ARMv7M

L’architecture ARMv7M est un⁤ élément clé dans le développement de nouveaux appareils. Sa puissance et son efficacité en​ font⁤ un choix privilégié pour les développeurs.

Et Si Nous Essayions ?

Face aux défis, il est ⁢toujours possible ‌d’explorer de ⁢nouvelles avenues. L’innovation⁣ est souvent le résultat de l’expérimentation.

Le Développement sur Matériel : Un Défi

CortexEmu à la Rescousse

CortexEmu ⁣est un émulateur qui facilite le développement sur ⁢du matériel PalmOS. Il permet aux développeurs de⁤ tester⁢ leurs ⁤applications sans avoir besoin d’un appareil physique.

Mais Vous Aviez Promis du⁤ Matériel Réel

Le passage au développement sur du matériel réel peut être frustrant. Les bugs matériels peuvent entraver le processus de développement et nécessiter des ajustements constants.

La Nécessité d’un Noyau

Pourquoi Pas Linux ?

L’utilisation de​ Linux comme noyau pour le‌ développement de PalmOS est ⁢une option intéressante. Cela permet de bénéficier d’une base solide tout en explorant ⁢de nouvelles fonctionnalités.

Les Défis du Code ARM

Le Code ARM : Un Problème Persistant

Le code ARM reste un défi majeur lors du portage. Les différences d’architecture peuvent entraîner des complications​ inattendues.

Écrire un⁣ Émulateur ‍en ‌C : Est-ce Lent ?

La question de la vitesse est cruciale. Écrire un émulateur‍ en ​C peut sembler⁤ lent, mais des optimisations peuvent améliorer les performances.

Est-ce Suffisamment Rapide Maintenant ?

Après de nombreuses itérations, il est essentiel de​ tester la rapidité de l’émulateur. Les performances doivent être ​à la hauteur des attentes ‍des utilisateurs.

Le Travail d’un JIT n’est Jamais Terminé

LDM et STM : Un Cauchemar ​à Jamais !

Les instructions LDM et STM peuvent poser de ‍nombreux problèmes lors de l’émulation. ⁣Leur complexité nécessite une attention ‍particulière.

Instructions Conditionnelles et Sauts

Les instructions conditionnelles et les sauts sont ⁤des⁤ éléments clés à prendre en compte lors de l’émulation. ‍Leur gestion correcte est essentielle​ pour garantir le bon fonctionnement des applications.

La Rapidité de PACE

Les Sauts Indirects

Les sauts indirects peuvent ralentir le processus d’émulation. ⁤Il est crucial de trouver des solutions adaptées à ce⁤ problème.

Une‍ Solution Spéciale pour un Problème Particulier

Trouver des solutions spécifiques à des problèmes particuliers est une compétence essentielle pour les développeurs.

Histoires de ​Reverse ⁤Engineering‌ de PalmOS

Support de la Carte⁤ SD

Le support des cartes SD est un aspect⁤ important du développement ⁣de ​PalmOS. Cela permet d’étendre les capacités de stockage des appareils.

Support du Port‌ Série

Le port série est un autre élément‍ clé. Il permet la communication entre les appareils et peut être⁣ testé par les développeurs.

Support de la Connectivité

Le développement de la connectivité est en cours. Les ⁢défis sont nombreux, mais les avancées sont prometteuses.

Support Audio

Le support‌ audio est⁢ un ‍domaine complexe. La gestion de l’audio sur‍ PalmOS nécessite​ des compétences techniques avancées.

Matériel Réel ‌: reSpring

L’Accessoire Ultime ⁣pour Springboard

reSpring est un accessoire innovant qui améliore les fonctionnalités des appareils PalmOS. Son développement a nécessité ⁢une attention‌ particulière aux détails.

Interfaçage‍ avec‍ le Visor

L’interfaçage ⁤avec le Visor est une étape ‍cruciale pour garantir la compatibilité avec les ‌appareils existants.

Conclusion : Où en Sommes-Nous ?

Le ⁣développement autour de PalmOS continue d’évoluer. Les​ défis sont nombreux, mais les ⁢opportunités d’innovation sont également présentes. Les développeurs doivent rester attentifs ‍aux évolutions technologiques pour tirer le meilleur parti de cette plateforme.

Le système d’exploitation PalmOS a été initialement conçu‌ pour fonctionner sur des processeurs‌ Motorola 68k, et ce, depuis ses débuts jusqu’à la version 4.x. ‌Avec l’arrivée de ⁣la version 5, Palm ​Inc‌ a décidé de migrer vers des ⁢processeurs ARM, offrant ainsi des performances nettement ⁣supérieures. Cependant, cette transition posait un⁣ défi majeur : que faire‌ des applications déjà existantes ?​ De nombreuses‌ applications‌ PalmOS avaient‍ été développées pour la⁤ version 4.x et compilées pour le processeur m68k. Pour résoudre ce problème, Palm Inc ‍a introduit le PACE (Palm Application Compatibility Extension). Ce système interceptait les appels système, tels que SysAppLaunch, ‌et émulait le processeur m68k, permettant ainsi aux anciennes ⁣applications de fonctionner sur la nouvelle⁤ architecture. Lorsqu’une application m68k effectuait un ​appel système, PACE ⁣traduisait les paramètres et appelait l’API native ARM, garantissant ainsi une exécution‌ rapide des applications, même si leur logique était émulée. En effet, les appareils PalmOS 4.x fonctionnaient généralement à 33 MHz, tandis que les ⁤appareils PalmOS 5.x atteignaient des vitesses de⁤ plusieurs centaines de MHz, ce qui minimisait les ralentissements. Cela était suffisant pour Palm Inc, car de nombreuses‍ applications intégrées, comme le calendrier et ​les contacts, restaient des‌ applications m68k.

Il est à noter que Palm Inc n’a jamais ⁢fourni de documentation sur la ​création d’applications ARM natives complètes pour PalmOS 5.x. Bien que cela fût possible, les ​meilleures pratiques n’étaient ‌pas documentées.⁣ La méthode officielle pour tirer parti de la vitesse des nouveaux processeurs ARM consistait à utiliser l’appel système PceNativeCall pour accéder‌ à un petit morceau ⁤de code ARM natif, que Palm‌ Inc appelait « ARMlet » puis « PNOlet ». Palm recommandait de n’utiliser cette ⁢méthode que pour les parties ‌de code les ‍plus critiques, et il était⁣ relativement difficile d’effectuer des appels système depuis ce code natif, nécessitant un retour ⁢vers PACE pour gérer les paramètres.

PalmOS 5.x⁣ a conservé de nombreux aspects de la conception de​ PalmOS 4.x, tels que le ‍tas partagé, l’absence ​de mémoire protégée et ⁢le manque de documentation sur le multithreading. Une nouveauté de cette‍ version était le support des modules chargés dynamiquement. En fait, ​chaque application ou bibliothèque ARM native dans PalmOS 5.x est un module, chacun ayant‌ un‌ identifiant unique dans la plage de 0 à 1023.‍ Cela⁤ explique probablement⁢ pourquoi Palm Inc n’a ⁣jamais documenté la création d’applications natives complètes, car cela aurait limité le nombre d’applications à 1024.

Modules, bibliothèques ​et pilotes

Le noyau du ⁣système​ d’exploitation,⁢ la ‌gestion‍ de ⁤la ‍mémoire, la plupart des pilotes et ​la‍ gestion bas niveau du processeur sont assurés par le DAL (Device Abstraction Layer). Le DAL (Module ID 0) ⁤exporte​ environ 200‍ appels système, selon la version de PalmOS. Ces ⁣appels concernent des fonctions de bas niveau, telles que l’état⁢ de la batterie, l’accès brut aux primitives de dessin à l’écran, la gestion des modules, etc. Au-dessus du DAL‌ se trouve le module⁤ Boot​ (Module ID 1), qui fournit de nombreux appels système orientés utilisateur. Ce module inclut ⁣des​ gestionnaires pour les données, la mémoire, les⁢ alarmes, les ⁣échanges, les bitmaps et les fenêtres. Enfin, le module​ UI (Module‌ ID 2) offre toutes les primitives d’interface utilisateur, telles ⁣que les contrôles, les formulaires, les ‍menus et les tableaux. Ensemble, ces trois modules constituent le ​cœur de PalmOS, et il serait même possible⁢ de démarrer un ROM contenant uniquement ces fichiers.

Ces trois premiers modules sont spéciaux, car ils sont toujours chargés et leurs fonctions exportées sont accessibles via un raccourci particulier. Pour les modules 0, 1 et 2, il est possible ​d’appeler une fonction exportée en exécutant deux instructions spécifiques. Ce raccourci facilite les appels ‍aux ‌fonctions système par les modules natifs, mais ne s’applique ⁤pas aux autres modules. Il‌ est également possible de modifier ces tables de pointeurs de‍ fonction, ce​ qui a souvent été fait par ce que l’on appelait des « hacks », et cela est également utilisé​ par le système d’exploitation lui-même.

PalmOS ne ⁢dispose d’aucune protection mémoire, ce qui signifie que tout code utilisateur peut accéder au matériel. Cela ‌est exploité par des pilotes, comme ⁢ceux des​ cartes SD, ⁣qui sont‍ généralement ‌des modules séparés et non ​intégrés au⁣ DAL. Le module Boot⁣ charge toutes les bases de données⁣ de ⁣ressources PalmOS de⁣ certains ⁢types au⁣ démarrage, permettant leur initialisation. Parmi‌ ces ⁣types,‌ on trouve les pilotes de slot, les pilotes de ‍système de ⁣fichiers, les pilotes de port série, et d’autres extensions. Cette séparation est pratique, car elle permet de remplacer⁣ ou de retirer⁢ facilement ces modules, bien qu’il existe des cas particuliers que les⁢ développeurs de PalmOS n’avaient pas anticipés.

Technologie vers le premier port non autorisé de PalmOS

Quelles sont les difficultés rencontrées ?

Comme‍ mentionné précédemment, aucune documentation sur ‌l’API native​ de PalmOS ‍5.x n’a jamais été publiée. Un petit nombre de personnes a réussi à comprendre certaines parties, mais personne ​n’a réussi ​à tout saisir.⁣ Cela est en partie dû au fait que de nombreuses fonctionnalités ‍ne sont pas pertinentes pour un ⁣développeur d’applications, ce ⁤qui a limité ⁤l’intérêt. Cela pose un problème pour ⁣ceux qui souhaitent créer un nouvel appareil. J’ai donc dû effectuer beaucoup de rétro-ingénierie pour ce projet, en ⁢explorant ‍des API ennuyeuses que je devais ⁤tout de même mettre en œuvre. De⁢ plus, il me fallait un noyau et du matériel fonctionnel.

Les⁤ formats de ROM sont‌ complexes

Pour commencer, j’ai développé un outil permettant⁤ de décomposer et de reconstruire des images de ROM PalmOS.⁢ Le format est assez complexe et a évolué entre les ​versions, mais après de nombreux efforts, l’outil « splitrom » peut ​désormais décomposer avec succès⁤ une ROM PalmOS allant ⁣des appareils pré-version 1.0 jusqu’aux ROMs PalmOS⁣ 6.0 Cobalt. L’outil « mkrom » ⁢peut également produire des images valides de⁣ PalmOS 5.x, bien que je n’aie pas cherché à créer d’autres‌ versions, car cela ne⁣ m’était pas nécessaire. À ce stade, j’ai pris un détour dans‍ le projet pour collecter des ROM PalmOS.

Exploration des Défis de Développement d’un DAL

Après avoir acquis une expérience significative avec divers appareils et prototypes, ⁢j’ai décidé de partager mes découvertes. Mon processus a commencé par l’analyse​ d’un ROM T|T3, où j’ai⁤ remplacé​ certains fichiers, réassemblé le tout et reflashé⁢ mon T|T3. À ma grande surprise, il a démarré⁣ ! C’était prometteur.

Écrire un DAL : Une Étape Cruciale

Ne disposant d’aucun matériel pour effectuer des tests, ni d’un noyau à utiliser, j’ai dû agir rapidement. La solution la plus efficace que j’ai trouvée était d’utiliser ​un processeur ARM ‍réel avec un noyau existant, en l’occurrence Linux. ⁣Comme⁢ mon ordinateur de bureau est basé sur un processeur⁢ x86, j’ai ‌eu recours à QEMU. J’ai développé ⁤un DAL rudimentaire qui enregistrait chaque fonction appelée avant de provoquer‍ un crash intentionnel. Au⁤ démarrage, il se comportait comme⁢ le‍ DAL de PalmOS : ​il ‌chargeait Boot et ⁤appelait PalmOSMain dans⁣ un nouveau thread. J’ai ensuite ‍créé⁣ une application simple qui utilisait mmap() pour mapper une zone de mémoire‍ à un emplacement spécifique, soutenue par « rom.bin » et‌ « ram.bin », et ⁣j’ai tenté de la ⁤démarrer. J’ai obtenu quelques messages de journalisation et‌ un crash,​ comme prévu. Cela semblait prometteur, mais ‍j’ai réalisé que ​la plupart des fonctions étaient nécessaires pour le démarrage. Une journée décevante…

Construction d’un DAL Minimal

Après plusieurs mois de ‍travail, j’ai réussi ⁢à implémenter la majorité du DAL, qui fonctionnait​ dans mon « runner » sous QEMU. C’était une configuration complexe. ​Étant donné que tout cela se déroulait​ dans un espace utilisateur sous Linux, ‍je devais faire appel au « runner » pour des tâches comme la création de threads. C’était un véritable‌ casse-tête. Le‌ code‌ actuel de rePalm prend⁢ encore en charge ce mode, mais je ne prévois pas de l’utiliser fréquemment pour ⁣diverses raisons. ‌Par exemple, le noyau Linux ne ⁤dispose pas de certaines API essentielles à PalmOS, comme la possibilité⁤ de désactiver et de réactiver‌ le changement de tâche. PalmOS demande ⁤parfois que la préemption soit⁢ désactivée, ce que​ Linux ne ⁢permet pas. De plus, PalmOS nécessite la capacité ⁤de mettre en pause et de reprendre un thread à distance,​ sans le consentement de celui-ci. La bibliothèque pthreads ne permet pas​ non plus cela. J’ai bricolé quelques solutions avec ‍ptrace, mais c’était chaotique. Anecdote amusante : comme ma machine est multi-cœur et que je n’ai jamais défini d’affinités,⁤ c’était la première fois que‌ PalmOS fonctionnait sur un ‌appareil multi-cœur. Je ne‍ m’en suis rendu compte⁤ que bien plus ⁤tard, mais c’était plutôt cool, non ?

Les ⁣Défis du Dessin

Un problème majeur est apparu. Pour une raison quelconque, des opérations‍ telles⁢ que‍ dessiner‌ des⁢ lignes, des rectangles,⁢ des cercles et des bitmaps faisaient toutes partie du DAL. Bien‍ que dessiner une ligne ne soit pas compliqué, des instructions⁢ comme « dessiner un⁢ rectangle arrondi avec une couleur de premier⁣ plan X et une couleur de fond Y, en utilisant le mode de dessin ‘masque’ sur ce canevas »⁤ ou « afficher cette image compressée en ​16 bits couleur pleine à 144 ppi⁣ sur ce ⁢canevas de​ 4 bits par pixel​ à 108‍ ppi avec dithering, en respectant les couleurs de transparence, et en utilisant‌ le mode ‘inverser' » deviennent rapidement complexes. Et oui, le DAL était censé gérer tout⁣ cela. Bien sûr, rien de tout cela n’était documenté‍ ! C’était un véritable cauchemar. Au début, j’ai traité ‍toutes les⁣ fonctions de dessin comme des NOP et j’ai simplement enregistré le texte dessiné pour suivre l’avancement de mon ⁤démarrage. Cela‌ m’a permis⁤ de mettre en⁣ œuvre de nombreuses autres OsCalls ​que le ⁣ DAL ⁣ devait fournir, mais j’ai finalement dû me confronter à la nécessité de dessiner. ⁣Ma première approche ​a été de mettre ​en œuvre les​ choses moi-même, en me⁣ basant sur les noms de fonction et​ un peu d’ingénierie inverse. Cette méthode a échoué rapidement – la matrice des possibilités était tout simplement trop vaste. Il y a 8 modes de dessin, 3 densités supportées, 4 formats de compression d’image, 5 profondeurs de couleur supportées et deux formats de‍ police. Il était impossible de‍ tout envisager, surtout sans moyen de s’assurer que ⁤j’avais raison. ⁤Je ne suis pas sûr que ⁢certains de ces modes aient jamais été utilisés par un logiciel existant,‌ mais peu importe -​ il fallait que ce soit pixel par pixel ‍exact ! Que faire ?

Une Inspiration​ Contestable

J’ai décidé d’adopter une solution‌ temporaire. ⁣J’ai ⁢désassemblé le⁤ DAL ‍ du Zire72. J’ai copié chacune des fonctions nécessaires, ainsi que toutes les fonctions qu’elles appelaient, et ainsi de suite. ⁣J’ai ensuite nettoyé leurs références directes aux variables globales du Zire DAL et entre elles, et j’ai regroupé le tout dans un énorme fichier‍ « drawing.S ». Ce fichier ⁤contenait ⁢plus de 30 000 lignes, et je‌ n’avais en grande partie aucune⁤ idée de son​ fonctionnement. Ou de son efficacité…

Et pourtant, ⁣cela a fonctionné ! Pas immédiatement, bien sûr, mais cela a fonctionné. Les ‍couleurs étaient déformées, ​des artefacts apparaissaient⁤ partout, mais j’ai réussi à ‍voir ​l’écran de calibration de l’écran tactile après le démarrage​ ! Succès, n’est-ce pas ? Eh bien, pas du tout. En fait, il s’est avéré qu’en raison⁢ d’optimisations, le code de dessin de PalmOS interagissait directement⁤ avec les variables globales du pilote d’affichage. ​À ce stade, mon‍ « pilote » d’affichage n’était⁤ qu’une zone⁤ de mémoire soutenue par une surface SDL. Cela a nécessité beaucoup⁤ de travail (un travail inutile – le pire genre) pour comprendre ‍ce qu’il recherchait et lui fournir ce dont il avait besoin. Mais après quelques semaines⁢ supplémentaires,⁢ le code de dessin ‍du⁣ DAL du Zire72 fonctionnait sous rePalm, et j’ai pu voir les éléments dessinés correctement. Après avoir mis en place ​un support rudimentaire ⁢pour l’écran tactile,‍ j’ai même pu interagir avec le dispositif virtuel et voir l’écran d’accueil. ‌Super, mais tout cela était ⁤vain. Je⁢ ne possède pas‌ ce code et je ‌ne peux pas le distribuer. Je ne peux pas non plus⁣ l’améliorer, l’étendre, le corriger ou même⁣ prétendre le comprendre entièrement. Ce n’était pas une voie à suivre.

Une Réécriture Méticuleuse

Il était temps de passer à⁤ l’action. J’ai réécrit le‌ code⁣ de dessin. Fonction par fonction.‍ Ligne par ligne. Instruction par instruction. J’ai testé chaque fonction après l’avoir remplacée du mieux que je pouvais. En cours de route, j’ai acquis une compréhension​ de la manière dont‌ PalmOS dessine,‍ des raccourcis pour les cas⁤ courants, etc. Cet effort ‍a duré deux mois, et à la fin, 30 000 lignes⁣ d’assemblage non commentées se sont transformées en 8 000 lignes de C. rePalm était enfin redevenu entièrement mon propre code ! Au passage, j’ai optimisé quelques éléments ​et ajouté le support pour une densité d’un et demi, une⁤ fonctionnalité que le DAL du Zire72 ne⁣ supportait pas. Parmi toutes les parties de ce projet, ⁢c’était la plus difficile à réaliser, car à la fin ​de chaque fonction décodée, comprise et réécrite, il n’y avait pas de progrès visible – l’objectif était simplement ⁤de ne rien casser, et il y avait toujours ‌des dizaines ⁣de ⁤milliers de lignes ⁤de code ⁤à désassembler, comprendre et‌ réécrire en C.

Création d’une Carte SD Virtuelle

Pour faciliter les tests, il serait pratique de ⁣pouvoir charger des programmes plus facilement dans l’appareil plutôt que de les intégrer⁤ dans ‍le ROM. J’ai développé un pilote de slot personnalisé qui ne faisait rien d’autre ⁢que de permettre l’utilisation de mon système de fichiers personnalisé. Ce système de fichiers⁣ utilisait des hyper-appels pour​ accéder au code dans le « runner » ‌afin d’effectuer⁣ des opérations de système de fichiers sur l’hôte. En gros, cela a créé un dossier partagé entre mon PC et rePalm. J’ai utilisé cela pour​ vérifier que la plupart‌ des logiciels et des jeux fonctionnaient ⁤comme prévu.

Compatibilité des ROMs⁣ de Dispositifs

Je pouvais tester⁣ n’importe quelle ROM ! J’ai essayé l’image pré-production de Tungsten T, l’image de LifeDrive, et même la ROM de Sony ‍TH55 ⁢a démarré ! Bien qu’il y ait eu⁣ des ajustements spécifiques à chaque⁣ appareil et à chaque version de l’OS, j’ai réussi à les appliquer automatiquement au moment de⁣ l’exécution. Par​ exemple, déterminer quelle version de ⁢l’OS était en ⁣cours d’exécution se faisait facilement en examinant le nombre de points‌ d’entrée‍ exportés de Boot. De plus, identifier si la‍ ROM était ​un appareil Sony ‍était simple en recherchant le module SonyDAL. Dans ce cas, nous refusons de la charger et exportons nous-mêmes des fonctions équivalentes. Pourquoi le DAL a-t-il besoin de connaître la version de l’OS ? Certains points d’entrée du DAL ont changé entre PalmOS 5.0 et PalmOS​ 5.2, et PalmOS 5.4 ou ultérieur attend des⁤ comportements supplémentaires de certaines fonctions existantes que⁢ nous devons prendre en ⁣charge.

Et maintenant, ‌c’est fini, n’est-ce pas ?

Vers la création du premier appareil PalmOS pirate

Comprendre le fonctionnement des appareils PalmOS 5.x

Pour saisir les défis ⁤rencontrés, ⁣il est essentiel d’explorer⁢ le ​fonctionnement des appareils PalmOS 5.x. Ces dispositifs étaient conçus ​pour des processeurs ARMv4T ou ARMv5,⁢ avec une capacité de mémoire flash ou ROM variant de 4 à 32‍ Mo, et une RAM allant de 8 à 128 Mo pour les allocations en temps réel et le stockage de données. La version 5.4 ⁢de PalmOS a introduit​ le NVFS, que ⁣nous‍ allons ignorer pour l’instant,‌ comme beaucoup ⁣d’entre nous l’ont souhaité à l’époque de sa sortie. ‌Les processeurs ARMv4T et ‍ARMv5 utilisaient deux ensembles d’instructions distincts : ARM et Thumb. ⁤Les​ instructions ARM mesurent chacune​ exactement​ 4 octets et constituent l’ensemble d’instructions original pour⁤ les processeurs ARM. En⁢ revanche, Thumb, introduit avec la version v4T, visait à⁢ améliorer la densité du code en utilisant des instructions de 2 octets, permettant ainsi de réduire la taille du code. Cependant, cette ⁤optimisation avait un coût⁣ : les instructions Thumb nécessitaient souvent plus d’étapes pour accomplir les mêmes tâches, et ‌elles avaient accès à⁣ moins de registres que leurs homologues ARM, ce ⁣qui pouvait entraîner un ‍code moins optimal.‌ Malgré cela, de larges portions de PalmOS ​étaient compilées en mode Thumb, car la vitesse ‍n’était pas ⁤toujours un facteur déterminant. À l’inverse, Sony avait choisi‌ de compiler l’ensemble de⁢ son système​ d’exploitation en mode⁣ ARM, profitant de ⁣puces flash plus grandes.

Les défis de⁤ la commutation entre ARM⁣ et Thumb

La ‍commutation ‍entre les⁤ modes ARM​ et Thumb dans les processeurs ARMv5 ⁢se faisait par certaines instructions qui⁢ modifiaient le flux de contrôle. Étant donné que toutes les ‍instructions ARM mesurent​ 4 octets et sont alignées sur ⁤une frontière de 4⁣ octets, toute adresse d’instruction ARM valide a ses deux ‌derniers ​bits à zéro. Les instructions Thumb,​ quant à elles, mesurent ⁢2⁣ octets et ont⁢ donc leur dernier bit à zéro. Cela a permis ⁣d’utiliser cette caractéristique pour la commutation de mode. L’instruction BX vérifiait le bit inférieur du registre‍ de destination : s’il était à 1, la destination⁢ était considérée comme Thumb, sinon comme ARM. D’autres instructions, comme POP et LDR, fonctionnaient de la même manière. Cependant, l’architecture ARMv5 est ​désormais obsolète, l’architecture ARM ayant évolué jusqu’à la⁢ version v8.x, qui propose des registres de 64 bits et ⁢un ⁢ensemble d’instructions totalement différent. Bien que les cartes de développement ARMv7 soient abondantes et peu coûteuses, leur documentation est souvent insuffisante, ​rendant leur utilisation complexe sans un noyau Linux.

Exploration des microcontrôleurs ‍ARM

Une ⁤alternative⁤ intéressante était d’explorer les microcontrôleurs, qui sont ⁣largement disponibles, bien documentés et économiques. ARM propose une gamme de cœurs sous la marque Cortex, tels que Cortex-M0, M3 et M4, qui utilisent un ensemble​ d’instructions Thumb/Thumb2. Ces cœurs⁢ sont‍ adaptés ‍pour des tâches complexes, prenant en charge des opérations de multiplication étendues et des flux de contrôle sophistiqués. Cependant, un inconvénient majeur‌ est que ces ⁣microcontrôleurs ne prennent en charge que les instructions Thumb, ce qui limite l’exécution de nombreuses fonctionnalités ‍de PalmOS, car⁢ chaque bibliothèque doit être⁢ entrée en mode ⁤ARM.​ Cela posait un⁣ problème significatif pour l’exécution d’un système d’exploitation non modifié.

Une solution innovante pour l’intégration⁣ de PalmOS

Face ‍à⁢ ces limitations, j’ai décidé d’étendre le format‌ de module ​de PalmOS pour permettre une⁣ entrée directe‍ en mode Thumb. J’ai également modifié le chargeur de modules pour qu’il reconnaisse les points d’entrée ⁢des bibliothèques pointant vers un‍ simple thunk ARM⁤ vers Thumb, ce qui‍ a ‌permis un démarrage presque ‌complet sans nécessiter de mode ARM.⁤ Cependant, cette solution n’était pas suffisante, car de nombreuses parties du système d’exploitation restaient en mode ARM, notamment des fonctions essentielles comme MemMove et MemCmp. L’objectif de faire fonctionner un PalmOS non modifié restait donc un défi de taille.

Défis de l’architecture ARM

Dans le domaine des systèmes d’exploitation et ​des applications, la possibilité d’éditer tout et n’importe où⁣ était limitée. Certaines fonctionnalités pouvaient être ajustées via SysPatchEntry. J’ai ainsi​ optimisé les⁣ fonctions ‍ MemMove et MemCmp pour améliorer la vitesse, en fournissant des implémentations optimales ⁣pour Thumb2. Cependant, d’autres éléments, comme la division‍ entière (qui n’est ⁢pas​ prise ⁢en charge par ARMv5), étaient disséminés dans presque toutes les bibliothèques et ne pouvaient pas être modifiés car ils n’étaient pas exportés. Nous avions réellement besoin d’un environnement capable d’exécuter des instructions⁣ ARM.

Exploration ‍des possibilités

Que se passerait-il si nous​ tentions de passer un microcontrôleur⁢ ARMv7M ⁣en mode ARM ? Le manuel est très explicite à ce sujet. Il CHANGERA le‌ mode, effacera le bit d’état indiquant que nous sommes en mode Thumb, et lorsqu’il ​tentera d’exécuter l’instruction suivante, il ‌déclenchera une UsageFault car il ne peut pas fonctionner dans ce mode. L’instruction Thumb BLX qui change toujours de mode est indéfinie dans ARMv7M, et si elle est ⁢exécutée, le processeur générera également une ‌ UsageFault, signalant une instruction invalide. Bien que cela semble décourageant, c’est en⁤ réalité une excellente ⁤nouvelle ! Nous pouvons intercepter ⁤une UsageFault… Si vous comprenez où ⁤je ‌veux en ⁤venir​ et que cela vous horrifie, merci de votre attention ! Nous reviendrons ⁤sur cette intrigue plus tard pour permettre à tout le‍ monde ‍de se​ mettre à jour.

Technologie :⁢ Le‌ besoin de matériel

CortexEmu : ⁤La solution

J’avais l’intention de faire fonctionner tout cela sur une puce ⁤de classe Cortex-M, mais je ne voulais pas développer directement sur celle-ci – c’était trop lent‍ et frustrant. De plus, je ​n’ai trouvé⁣ aucun bon émulateur pour les puces de classe Cortex-M. À ce stade, j’ai pris une pause de deux semaines pour créer ‍CortexEmu. ​Cet émulateur‍ fonctionnel pour Cortex-M0/M3/M23 reproduit ‌fidèlement le matériel‍ Cortex. Il dispose d’un stub GDB pour le débogage, ⁤d’une émulation matérielle rudimentaire pour afficher un ⁣écran, et prend en charge un RTC, ⁤une console et un écran tactile. ⁣Il gère les modes privilégiés et non privilégiés, et émule également ⁢l’unité de protection de la mémoire (MPU). CortexEmu reste⁢ le meilleur moyen de développer rePalm.

Attendez ! Vous avez‍ promis du matériel réel

Oui, oui, nous y arriverons, mais cela prendra ‌encore plusieurs mois dans l’histoire, ⁣alors soyez ⁢patients !

Technologie : La nécessité d’un noyau

Pourquoi ne pas utiliser Linux ?

PalmOS ⁣nécessite ​un noyau avec un‌ ensemble particulier de ‍primitives. Nous avons déjà abordé certaines (mais pas toutes) des raisons ⁢pour lesquelles Linux est ​un choix peu judicieux. De plus, la version Linux compatible avec Cortex-M3 est lente ET volumineuse, ce qui en fait une ‍option inacceptable. Alors, quelle alternative avons-nous ?

J’ai finalement décidé d’écrire mon propre noyau.‌ Il est simple et fonctionne bien. Il​ peut s’exécuter sur n’importe quel processeur de ​classe Cortex-M, prend⁤ en charge le multithreading ⁢avec priorités, ⁣des ⁤minuteries précises, des​ mutex, ‍des sémaphores, des groupes ‍d’événements, des boîtes⁢ aux lettres, et toutes les primitives que‌ PalmOS exige, comme la possibilité de suspendre des threads et de désactiver le changement de ⁢tâche. Il utilise également le⁢ MPU ‍pour ajouter des mesures de sécurité de base, ⁣comme des gardes de pile. ⁤De plus, ⁤il offre un excellent support pour le ‍stockage local des threads,⁤ ce qui sera utile par la suite. Pourquoi créer mon propre noyau ‌alors qu’il en⁣ existe‌ déjà tant ? Aucun des noyaux disponibles ⁤ne possédait ‌vraiment les ‍primitives dont j’avais besoin, et les ajouter aurait pris tout autant⁤ de temps.

Technologie ⁢: Les défis du code ‍ARM

Le code ARM reste problématique

PalmOS ne‌ parvenait​ toujours pas à démarrer complètement jusqu’à l’interface utilisateur à cause​ du code ARM. Mais, comme je l’ai mentionné⁣ précédemment, nous pouvons intercepter ⁤les tentatives d’accès au mode ARM. J’ai donc écrit un gestionnaire de UsageFault ​ pour ⁣cela, puis… je ⁢l’ai émulé.

Vous ne voulez pas dire… ?

Oh, mais​ si. J’ai ​développé un émulateur ARM qui lit chaque instruction et⁤ l’exécute, jusqu’à ce que le code sorte du mode ARM, ⁤moment auquel je quitte l’émulation pour‌ reprendre l’exécution native. Les⁣ détails de ce fonctionnement sont fascinants, car l’émulateur nécessite ⁣sa propre pile et ne peut pas s’exécuter sur la pile du code émulé. ⁢Il⁢ doit également y avoir un ⁤espace pour stocker les registres‌ émulés, car nous ne pouvons ⁢pas simplement les garder dans ​les registres ‍réels (il n’y a pas assez de registres pour les deux). Quitter l’émulation est‌ également un défi, ⁤car il faut charger tous les registres et le registre d’état en une seule opération atomique. Ce n’est pas trivial sur Cortex-M. Quoi⁢ qu’il en soit, « emu.c » et « emuC.c » contiennent ‌le code – n’hésitez ⁢pas à explorer.

Écrire un émulateur en C n’est pas lent ?

Vous n’avez aucune idée ! L’émulateur était effectivement lent. J’ai instrumenté CortexEmu pour compter les cycles et j’ai constaté qu’il fallait en moyenne⁤ 170 cycles du processeur ‍hôte pour émuler une seule instruction ARM. Ce n’était pas suffisant. Il est bien connu que les émulateurs écrits en C sont lents. Les ‌compilateurs C ne sont pas très efficaces‍ pour optimiser le code des émulateurs.⁤ Que faire alors ? J’ai donc‌ réécrit le cœur de l’émulateur en⁢ assembleur. En fait, je l’ai ⁣fait ‌deux fois⁢ : une⁤ fois ‌pour ARMv7M (cible Cortex-M3) et une fois​ pour ARMv6M (cible‍ Cortex-M0). La vitesse ⁣s’est considérablement améliorée. Pour le cœur M3,‍ j’atteignais en moyenne 14 cycles par instruction, ‍et pour le ⁢M0, 19. Une ⁢performance d’émulateur​ très respectable, si je puis⁣ me permettre ⁤de le ⁣dire.

Est-ce assez rapide ‍maintenant ?

Comme mentionné précédemment, sur les appareils PalmOS d’origine, le code​ ARM était généralement plus rapide que⁣ le code Thumb, donc la plupart des routines les‌ plus critiques étaient écrites en ARM. ‌Pour nous, le code ARM est 14 fois plus lent que le code Thumb. Ainsi,​ le code censé être le plus rapide est devenu lent. Mais examinons ce code⁤ de plus près. Les routines de division en font partie. ARMv7M gère la division en matériel, mais ARMv5 ne le faisait pas (et ARMv6M non plus). Ces ‍routines prennent environ une ⁢centaine de cycles en mode ARM. Les fonctions MemMove, ⁢ MemMSet ‌ et MemCmp dont nous avons ​déjà⁣ parlé ne ⁢nous préoccupent pas car nous les avons remplacées, mais de nombreuses bibliothèques​ avaient leurs propres copies internes ⁣que nous ne pouvons pas⁤ modifier. Je suppose que le compilateur préfère en général intégrer ses propres « memset » et « memcpy ». ‍Cela représentait une grande partie de l’utilisation du code ARM lors du processus de démarrage. Heureusement, ‌toutes ces fonctions sont identiques partout…

Pouvons-nous donc ‌identifier certaines de ces fonctions dans le code de ⁣l’émulateur et​ exécuter des routines natives‌ plus rapides ? J’ai fait cela et le temps de démarrage a effectivement diminué. Le⁢ coût⁢ moyen par instruction a ‍augmenté en raison de l’identification, mais le temps de démarrage a été réduit. Super. Mais que se passe-t-il après le ⁤démarrage ? Après le démarrage, ⁤nous⁢ rencontrons le ‍véritable ​défi… l’émulateur m68k de PACE est écrit en ARM. 60 kilooctets de code clairement​ écrit à la main avec de nombreuses astuces astucieuses. ⁣Ces astuces deviennent problématiques lorsque vous devez les émuler… Cela signifie que chaque application m68k (qui est la plupart d’entre elles) fonctionne ⁤désormais sous double émulation. Pas idéal… Et aussi : lent. Il fallait agir. J’ai envisagé de réécrire PACE, mais cela n’est pas une solution viable – il existe de nombreuses bibliothèques ARM et je ne peux pas toutes‌ les réécrire. De plus, comment puis-je prétendre exécuter⁣ un système d’exploitation non modifié‍ si je remplace chaque élément ?

Il⁣ existe une autre méthode pour⁢ rendre le code non natif plus rapide…

Technologie : Une solution innovante

Traduction à la volée

PACE contient‍ beaucoup de code statique très sollicité. Sur les appareils réels, il réside ‍dans la ROM et ne change ‍pas. La plupart des bibliothèques‌ sont ⁢identiques. Que pouvons-nous faire pour améliorer la vitesse d’exécution⁤ ? Les traduire en un format que nous pouvons ⁢exécuter nativement,‌ bien ⁤sûr. La plupart des ‌gens hésiteraient à ⁣entreprendre⁤ seuls la tâche ⁤d’écrire​ un traducteur à la volée. Mais⁤ cela ne fait que parce qu’ils sont…

Introduction aux JIT : Comment démarrer ?

Pour initier un JIT, nous procédons de manière similaire ‍à celle utilisée pour‍ un émulateur. Nous mettons ⁢en place⁣ un cache de‌ traduction par thread (CT) qui stockera nos traductions. Pourquoi par thread ? Cela permet‍ d’éviter que l’un d’eux ne purge le cache pendant qu’un autre est‍ en cours d’exécution,‌ ce⁣ qui pourrait entraîner des problèmes. Le CT contiendra des unités de traduction (UT), chacune⁤ représentant un‍ code traduit. Chaque UT inclut l’adresse ARM d’origine⁣ et le code Thumb2 valide. De plus, une ‍table⁢ de‍ hachage sera utilisée pour‌ associer les ‌adresses ⁣ »ARM » d’origine à un seau où la première UT correspondant à ‌cette valeur de⁢ hachage est stockée. Chaque seau est une liste chaînée, et nous utilisons ⁣4096 seaux, un‍ chiffre configurable. Un hachage rapide et​ simple est ‍appliqué, et les tests‍ sur un échantillon représentatif d’adresses ont montré une bonne‌ distribution. Ainsi, chaque fois qu’un‍ UsageFault se produit,⁤ indiquant ⁤une tentative ‍d’entrée en mode⁣ ARM, nous consultons la table de hachage ⁣pour l’adresse souhaitée. En cas de⁢ succès, ​nous remplaçons simplement le PC dans le cadre d’exception par le pointeur « code » de l’UT correspondante et continuons l’exécution du code natif rapidement. Parfait ! Que se passe-t-il ⁣si nous n’obtenons ⁣pas ‌de correspondance ? Nous ​sauvegardons alors l’état et remplaçons le PC dans le cadre d’exception par l’adresse du code de​ traduction (nous ne‌ voulons pas traduire en mode noyau).

Comprendre les instructions ARM

Le front-end d’un ⁣JIT doit essentiellement ingérer les instructions ARM et les interpréter. Nous allons intercepter celles que nous ne comprenons pas et​ tenter de traduire toutes celles⁣ que nous maîtrisons. Cependant, nous rencontrons un premier obstacle.⁤ Certains jeux utilisent⁣ des instructions non valides. Par exemple, le jeu « Bejeweled » contient du code ARM qui tente d’exécuter LDMDB R11, {R0-R12, SP, PC}^. Ignorons ‍le fait que R0-R2 et R12 n’ont pas besoin d’être sauvegardés, ce qui est inefficace, et notons que cette instruction n’est ⁤pas valide en mode ⁣utilisateur. Le⁣ petit symbole‍ caret à la fin signifie⁢ « transférer également SPSR vers CPSR« . Cette demande est invalide en mode⁣ utilisateur, et le manuel de référence de l’architecture‌ ARM précise clairement que son exécution en mode utilisateur aura des effets indéfinis. Cela explique‌ pourquoi Bejeweled ne fonctionnait pas sous rePalm avec QEMU, qui a correctement refusé d’exécuter cette instruction. J’ai donc sorti un⁤ appareil Palm d’un tiroir pour tester ce qui se passe réellement lors de son exécution. Il s’avère que cela est simplement ignoré. Mon JIT‌ fera ⁤donc de même. Mes cœurs d’émulateur n’ont eu⁢ aucun problème​ avec cette instruction, car étant ⁤indéfinie, la traiter comme si elle n’avait pas de caret était sûr, et​ ils n’ont donc même pas vérifié le bit indiquant cela.

Heureusement, ‌ARM ne possède que quelques formats d’instructions. Malheureusement, ils sont tous assez complexes. La bonne nouvelle, c’est que le décodage est relativement simple.​ Presque chaque instruction ARM est conditionnelle, et les 4 bits supérieurs déterminent si elle s’exécute ou non. Les opérations de traitement de données ⁢utilisent ​toujours trois opérandes⁤ :‌ registre de ‍destination, registre source et « opérande », qui est le mode d’adressage 1⁤ d’ARM. Cela peut être‌ une ‍valeur immédiate de certaines formes, un registre, un registre décalé par une valeur‍ immédiate, ou un registre décalé par un autre registre. Par exemple, on peut exécuter ADD R0, ⁣R1,​ R2, ROR⁤ R3. Cela peut ‌sembler ​intimidant ! La définition des indicateurs est optionnelle. Le chargement et le stockage de bytes ⁣ou de mots utilisent le mode d’adressage 2, qui permet d’utiliser un registre plus ou moins une ⁣valeur immédiate, ou un registre plus ou moins un autre ⁤registre, ou un registre plus ou moins un registre décalé par une ⁢valeur immédiate. Tous ces modes ‌peuvent être indexés, post-indexés ou indexés avec écriture, ce qui permet des instructions complexes comme LDR R0, [R1], ⁣R2,⁣ LSL #12.⁤ Le chargement et ‍le stockage de demi-mots ou​ de données signées utilisent le mode d’adressage 3, qui est similaire ‍au mode 2, mais sans ⁤décalage de⁢ registre. Ce mode ⁢est également utilisé​ pour les instructions LDRD ⁢et STRD que⁢ certains cœurs‍ ARMv5 implémentent (partie de l’extension DSP optionnelle). Le mode ⁣d’adressage⁢ 4 est utilisé pour⁤ les instructions LDM et STM,‌ qui ⁢sont‍ redoutables en ‌raison de leur ​complexité et de leurs nombreux cas particuliers. Elles peuvent charger ou stocker n’importe quel sous-ensemble de registres à une adresse⁢ de base donnée avec incrémentation ⁢ou décrémentation avant ou après, et écriture optionnelle. Elles sont souvent utilisées pour les opérations de pile. Enfin, les branches sont toutes encodées de manière simple et se ​décodent facilement. Ouf !

Les défis de la traduction des instructions Thumb2

Au départ, on pensait que la traduction ne serait pas si difficile. Les instructions semblent similaires, et cela ne devrait pas poser trop de problèmes. Puis la réalité a frappé. Thumb2 impose de nombreuses restrictions sur les opérandes. Par exemple, SP ne peut pas être traité comme un registre​ général, et LR et PC ne peuvent jamais être chargés ensemble. ‍De plus, il n’offre pas la⁢ même ‌capacité que le ​mode d’adressage 1 pour décaler‌ un registre par⁣ un autre comme troisième opérande dans une opération ALU. Il ‌ne permet pas de⁢ décaler un troisième registre‍ de plus de 3, contrairement au mode 2 ​d’ARM. Je ne vais ​même pas aborder les instructions LDM et STM ! De⁤ plus, il y ‌a le problème de ne pas​ permettre au code traduit de ‌savoir qu’il ‍est ⁤en cours de traduction. Cela signifie qu’il doit toujours croire qu’il s’exécute à partir de ‍son emplacement⁣ d’origine, et s’il ​se lit lui-même,⁣ il doit voir des instructions ARM. Cela implique que nous ne pouvons jamais divulguer la valeur réelle de PC ‍ dans un état exécutable.‌ En ⁤pratique, cela signifie que nous ne pouvons jamais émettre une instruction BL, et chaque fois que PC est lu, nous devons produire une ​valeur immédiate équivalente à ce que PC ‌aurait été si le ​code ARM ‍avait été exécuté à son emplacement réel en mémoire. Pas très amusant…

Les instructions LDM/STM de Thumb2 manquent​ en fait de la moitié des ⁣modes disponibles dans ARM ‌(modes ID et DA), ce qui​ nous oblige à étendre ces instructions à beaucoup plus de code. De plus, Thumb impose‌ des limites sur l’écriture ‌qui ne⁣ correspondent pas à celles d’ARM (plus⁤ strictes), et⁣ il est impossible d’utiliser SP dans l’ensemble des registres,‌ ni de stocker PC de cette manière dans Thumb2. À ce‍ stade, ⁣il devient évident que ⁤la tâche de traduire instruction par instruction ne sera ⁤pas ⁢simple.⁢ Nous aurons besoin d’endroits pour stocker des valeurs immédiates temporaires, nous devrons réécrire de nombreuses instructions, et tout ⁣cela sans​ provoquer d’effets secondaires. ​Et cela doit ⁤également être rapide !

Les complexités​ des⁢ opérations LDM et STM

Fonctionnement des⁤ LDM et ⁤STM en ARM

ARM dispose‍ de deux opérations à plusieurs registres : LDM et STM. Chacune d’elles​ propose plusieurs modes d’adressage. Tout d’abord, il y a l’ordre : croissant​ ou décroissant dans les adresses (c’est-à-dire, ‌le registre de base indique-t-il où stocker le registre le moins ⁢numéroté ‌ou le plus élevé). Ensuite, il s’agit de savoir si le registre de base‌ doit être utilisé tel quel ou s’il doit être ⁤incrémenté​ ou décrémenté au ⁣préalable. Cela nous donne les quatre modes de base : IA (« incrément après »), IB (« incrément avant »), DA (« décrément après »), DB (« décrément avant »). De plus, il est optionnel de mettre à​ jour l’adresse de base dans le registre de⁢ base. Bien sûr, il existe des cas particuliers, comme la valeur qui est stockée si le registre de base avec mise à jour est utilisé, ou quelle valeur le registre ‍de base aura⁤ s’il est chargé alors que ‍la mise à jour est également spécifiée. La spécification ARM définit explicitement certains⁣ de ces cas ‍comme ayant des ‍conséquences imprévisibles.

Pour la‌ pile, ARM utilise​ une pile descendante complète. Cela signifie qu’à tout moment, le registre SP pointe vers la dernière position de pile déjà utilisée. Ainsi, pour dépiler une ‌valeur, ⁤vous⁤ la chargez depuis [SP], ​puis vous incrémentez SP de 4. Cela se fait en​ utilisant une instruction LDM.

Comprendre le fonctionnement des instructions LDM/STM dans Thumb2

Pour introduire le sujet, il est essentiel de comprendre comment les valeurs sont gérées dans la pile. Pour ajouter une valeur à la pile, il faut ​d’abord diminuer le registre de pile (SP) de 4, puis ​stocker ⁢la valeur souhaitée à l’adresse indiquée par SP. Cela correspond à une ​instruction STM utilisant un mode d’adressage DB. Les modes IB et DA ne sont généralement pas utilisés pour la gestion de la ⁣pile dans le code ARM classique.

Les limitations de Thumb2

Pourquoi est-ce important ? Lors de la conception de l’ensemble d’instructions Thumb2, ARM a ​fait des choix sur les fonctionnalités à inclure. Cela a conduit à l’exclusion de certaines options moins courantes. En effet, Thumb2 ne prend pas en charge les‌ modes IB ⁤et DA. De plus, il est interdit d’utiliser​ les registres PC ou SP dans la liste des ⁣registres à stocker⁢ lors d’une instruction STM. ⁤Il⁣ est également impossible de charger SP​ avec LDM, et si une instruction LDM charge⁣ PC, elle ne peut pas charger LR en même temps, et vice⁤ versa.⁤ En outre, PC ne peut⁢ pas être utilisé comme registre de base,⁣ et la liste des registres ‍doit contenir​ au moins deux éléments. Cela constitue une liste partielle des limitations de⁤ Thumb2 par rapport ⁤à ARM.

Complexité de⁢ la traduction ⁣des instructions

Les instructions qui se traduisent⁢ bien d’ARM à Thumb2 ne sont ⁢pas toujours simples à convertir. Par exemple,​ le stockage de PC est‌ complexe, car il faut un registre temporaire pour conserver ‍la valeur attendue de PC avant⁣ de l’ajouter à la pile. Les‍ registres sont empilés dans un ordre précis, donc le choix du registre temporaire peut affecter la relative ⁤position des autres registres, ‌nécessitant parfois de diviser le stockage en ​plusieurs opérations.⁤ Si le stockage implique SP, il faut également ajuster en conséquence. Dans le ‍cas d’une instruction STMDB SP ​(c’est-à-dire ⁢PUSH), il‌ devient difficile de préempiler ⁢un registre temporaire.

Les défis des instructions atomiques

Une autre complication réside dans le fait que LDM/STM est censé agir comme une instruction atomique⁣ pour l’espace utilisateur. Cela signifie qu’elle doit être soit annulée, ⁤soit reprise au‌ niveau système.​ Cependant,​ dans les puces Cortex-M utilisant Thumb2, SP a une importance ⁢particulière, car le cadre d’exception y est stocké.⁤ Cela implique que SP doit toujours ‌être valide, ​et toute donnée stockée en dessous de SP n’est pas garantie de persister, car une interruption peut survenir à tout moment. Heureusement, sur ARM, il était ‍également déconseillé de stocker des données en dessous de SP, ce qui était rare. Un exemple notoire est ⁣un morceau ⁤de code PalmOS qui le fait, mais pour d’autres raisons, ce code a été ​remplacé.‌ Dans tous les autres cas, ‌le JIT émettra‍ un avertissement si une tentative de chargement ou de ‍stockage​ en ⁣dessous de SP est effectuée.

La complexité de la traduction LDM/STM

  1. Vérifier si l’instruction entraîne un ‌comportement indéfini ou ⁣n’est pas définie selon le Manuel de Référence de l’Architecture ARM. Si c’est le cas, enregistrer une erreur⁢ et abandonner.
  2. Déterminer si elle peut être émise comme une instruction Thumb2⁢ LDM/STM, c’est-à-dire si ‌elle respecte toutes ​les‍ restrictions imposées par Thumb2, ‌et si⁤ PC n’est pas stocké, émettre une⁤ instruction Thumb2 LDM/STM.
  3. Vérifier si elle peut ‌être‍ émise comme‍ LDR/STR/LDRD/STRD tout en respectant les limites ​de Thumb2. Si c’est le cas, émettre cette ⁢instruction.
  4. Traiter quelques⁣ cas spéciaux pour des traductions ⁣rapides d’instructions courantes non couvertes par les étapes précédentes.
  5. Pour les modes non pris en charge IB et DA, s’ils ne nécessitent pas de retour d’écriture, ils peuvent⁢ être réécrits en termes de modes pris en charge.
  6. Si l’instruction charge SP, il‌ est impossible ‌d’émettre une⁣ traduction ‌valide en raison de l’utilisation de SP dans ARMv7-M. Pour ce ‍cas particulier, le JIT émet une instruction indéfinie et nous l’imitons. Heureusement, aucun code‍ courant ne l’utilise ‍!
  7. Enfin, suivre le ‌chemin générique lent :
    1. Générer une liste de registres à charger/stocker et à quelles adresses.
    2. Calculer le retour d’écriture si ⁣nécessaire.
    3. Si ‍besoin, allouer un ou deux registres temporaires (deux si PC et SP sont stockés) ‌et ⁤sauvegarder leur contenu sur la pile.
    4. Pour tous‍ les registres restants à charger/stocker, déterminer ‌combien peuvent être chargés/stokés simultanément et procéder. Cela implique d’émettre une série d’instructions ‌: LDR/STR/LDRD/STRD/LDM/STM jusqu’à ​ce que tout soit fait.
    5. Si⁣ des‍ registres temporaires ont ⁣été alloués, les​ restaurer.

Instructions conditionnelles et leur complexité

Les modes d’adressage complexes, ​notamment‍ le⁤ mode 1, posent également des défis.⁤ Grâce aux modes de rotation par registre, un ⁣registre temporaire est‌ nécessaire pour calculer la valeur avant de l’utiliser. Si le registre de destination ⁢n’est pas utilisé, il peut servir de ⁤stockage temporaire, à condition qu’il ne soit pas également l’un des autres opérandes sources, ou SP, ou PC. Cela complique encore la situation.⁤ Si PC est également un opérande, un ​registre temporaire est requis pour charger‌ la valeur « factice »​ de PC avant​ de⁣ pouvoir effectuer ‍des opérations. Cela peut rapidement devenir un casse-tête. Pour ‍plus de détails, consultez « emuJit.c ». nous faisons de notre mieux pour éviter ‌de déverser des données sur la pile, mais parfois, cela‍ s’avère inévitable.

Cette complexité s’applique également à certains modes d’adressage complexes.⁤ Thumb2 a optimisé ses‌ instructions pour les cas courants, rendant ⁢les cas moins fréquents‌ très ​difficiles à traduire. Il est encore‍ plus‌ difficile de trouver des ‍registres temporaires, car si nous empilons quoi que ce soit, nous devons en tenir compte si‍ notre registre⁤ de ‌base est SP. les traductions efficaces sont réservées aux cas courants, tandis que les cas rares sont ⁤souvent négligés. Un​ cas particulier concerne les chargements ⁤basés sur PC, utilisés pour charger des données constantes. Dans la plupart des cas, nous intégrons les données constantes dans les traductions produites pour des raisons de rapidité.

Instructions Conditionnelles dans Thumb2

Le système Thumb2 offre des mécanismes⁣ pour établir des instructions conditionnelles grâce à ⁣l’instruction IT, qui permet de rendre les 1 ‌à 4 instructions suivantes conditionnelles. J’ai choisi⁤ de ne pas ​l’utiliser, car cela modifie également la manière ​dont les ‌indicateurs‍ sont définis par les instructions Thumb de 2 octets, et je ne souhaitais pas créer des cas particuliers. De plus, il arrive que 4 instructions ne suffisent pas pour une ⁤traduction⁤ complète. Par exemple, certaines instructions STMDA ⁢peuvent s’étendre sur ⁣environ 28 ⁤instructions. Dans ces cas, j’émet⁢ un saut de polarité opposée (condition) sur la traduction. Cela fonctionne, ‍car ces sauts ne font également​ que 2 octets pour toutes les longueurs‌ de ⁣traduction possibles.

Sauts et​ Appels

Ce domaine est particulièrement fascinant.⁤ En gros, il ​existe ‍deux types de sauts/appels : ceux dont les destinations sont connues au moment de la traduction et ​ceux dont elles ne le sont pas. Les sauts avec des adresses connues sont relativement simples à gérer. ‌Nous recherchons l’adresse de destination dans notre TC. Si elle est ⁣trouvée, nous émettons un saut ⁣direct vers cette unité de traduction (TU). Cela ‍rend les boucles ⁢fréquentes très ‌rapides,⁣ car aucune sortie du⁢ code traduit n’est nécessaire. Les sauts indirects ou ​calculés sont ​moins ⁢courants, ce qui pourrait laisser penser qu’ils​ ne sont pas ‌très importants. ⁤Cependant, c’est une‌ erreur, car un type de ‌saut indirect se produit fréquemment ⁢: ⁢le retour de fonction. Au ⁢moment de la traduction, nous ne savons pas où le⁤ retour va se ⁣diriger. Comment gérons-nous⁤ cela ? Si le code‍ charge directement PC, tout fonctionne comme prévu. Soit il s’agit d’une adresse ARM et notre ⁢gestionnaire UsageFault ⁣ s’en occupera, soit il s’agit d’une adresse Thumb et notre CPU y sautera directement. Une optimisation ⁣existe pour le cas où une instruction ​ BX LR ‍ est rencontrée. Nous émettons alors un saut direct vers une fonction qui recherche LR ⁣dans le ‌hachage,‍ ce⁣ qui nous fait gagner le temps nécessaire pour gérer une exception et y​ revenir (environ 60 cycles). D’autres optimisations sont possibles et seront ajoutées, mais ‌pour l’instant, c’est ainsi que cela fonctionne. Que faire pour un saut dont la destination est connue mais qui n’a pas encore été traduite ? Nous ​laissons un marqueur, c’est-à-dire une instruction que ​nous savons être indéfinie, suivie de l’adresse cible. Ainsi, si le saut est effectivement pris (ce qui n’est pas toujours le cas), nous prendrons l’exception, traduirons, puis remplacerons cette instruction indéfinie⁢ et le mot qui la suit ‌par un saut réel. La prochaine fois, ce saut sera rapide, sans provoquer ⁤d’exceptions.

Processus de‍ Traduction d’une TU

Le processus est simple : nous traduisons les​ instructions jusqu’à atteindre une instruction que nous​ considérons comme terminale. Qu’est-ce qui est​ terminal ? Un saut inconditionnel est ‌terminal. Un ⁣appel ‌l’est⁣ aussi (qu’il soit conditionnel ⁢ou non). Pourquoi ? Parce qu’il se peut que quelqu’un revienne⁢ de cet appel, et nous⁤ préférons que le code de retour soit dans​ une nouvelle TU afin de pouvoir ​le retrouver lors du retour. Une écriture inconditionnelle dans PC de quelque sorte que ​ce soit est également terminale. Il y a une astuce pour les sauts vers des endroits proches. En traduisant une TU, nous ​gardons ⁤une trace des dernières instructions traduites et de leurs traductions. Ainsi, si nous voyons un saut court en arrière, ⁤nous pouvons littéralement intégrer un​ saut vers cette traduction, créant​ ainsi une traduction très rapide de cette petite boucle. Mais⁤ qu’en est-il des sauts courts en avant ‍? Nous‍ les mémorisons également, et si avant d’atteindre notre instruction terminale, nous ‌traduisons une adresse⁣ que ‌nous avons mémorisée d’un saut précédent dans cette même TU, nous retournerons et remplacerons ce saut par ⁢un ⁤saut court vers ici.

Que faire si le TC est plein ?

Vous aurez peut-être remarqué ⁤que j’ai mentionné que nous émettons des sauts entre les TUs. « Cela ne ⁢signifie-t-il pas, »‌ pourriez-vous demander, « que vous ne pouvez pas simplement supprimer‌ une TU ? » C’est exact. Il s’avère que suivre quelles TUs sont beaucoup utilisées et lesquelles ne le‍ sont pas est trop complexe, et ⁢les avantages des sauts inter-TU sont trop importants pour être ignorés. Que faisons-nous donc⁤ lorsque le TC est plein ? Nous le vidons – nous le⁢ jetons littéralement. Cela aide également à s’assurer que les anciennes traductions qui ne sont plus nécessaires sont finalement éliminées. Le TC ​de⁤ chaque ⁤thread croît jusqu’à une taille maximale. ⁤Certains threads n’exécutent jamais beaucoup d’ARM et finissent ⁣avec des TCs petits. Le TC du thread principal de l’interface utilisateur atteindra pratiquement toujours la taille maximale (actuellement 32 Ko).

Améliorations du JIT

Après avoir mis en place ​le JIT, j’ai entrepris de le réécrire. La version initiale contenait de nombreuses valeurs magiques et des lacunes (des cas‌ qui pouvaient se produire dans ‍un code légitime mais qui seraient mal‍ traduits). Elle émettait parfois des opcodes invalides que le Cortex-M4 exécutait⁤ malgré les documents⁤ indiquant qu’ils n’étaient pas autorisés. Le‌ JIT a été divisé en deux parties. La première était le​ frontend qui ingérait les instructions ARM, maintenait⁣ le TC et suivait divers⁣ autres états. La seconde était le backend. Le backend avait une fonction pour chaque mode d’adressage​ ARMv5‌ ou⁤ format d’instruction possible, et pour toute instruction ARMv5 valide, il pouvait produire une séquence d’instructions ARMv7M pour ​accomplir la même tâche. Pour les cas courants,⁣ la séquence était bien optimisée,⁤ tandis que pour les cas moins fréquents, elle ⁣ne l’était pas. Cependant, le backend⁢ gère TOUTE demande ARMv5 valide possible, même des instructions étranges comme RSBS PC, SP, PC, ROR SP. Personne de ‌sensé ne produirait jamais⁤ cette instruction, mais le backend la traduira correctement. J’ai ⁢écrit des tests et les ai exécutés ‍automatiquement pour vérifier que toutes les ⁤entrées possibles sont traitées ⁢correctement.⁤ J’ai également optimisé le chemin le plus fréquent dans tout le système – ⁣l’émulation de l’instruction​ BLX en mode Thumb. Cela a permis un‍ gain de 50 cycles, ce qui a eu un impact notable sur les performances. En outre, j’ai remarqué que souvent, le⁤ code Thumb utilisait un BLX ‌ simplement pour sauter à un OsCall (qui, en raison de l’utilisation⁢ de R12 et R9, ne peut pas être écrit en mode Thumb). Le ​nouveau gestionnaire BLX détecte cela et évite l’émulation en‌ appelant directement l’OsCall requis.

J’ai ensuite développé un sous-backend pour l’extension EDSP (instructions ARMv5E)‍ car certaines applications Sony les utilisent. La raison d’un sous-backend séparé est⁢ que l’ARMv7E (Cortex-M4) dispose d’instructions que‍ nous pouvons utiliser pour traduire les instructions EDSP ​de manière​ très efficace, ‌tandis que ‍l’ARMv7 (Cortex-M3) ne⁢ le fait ‍pas et nécessite des séquences d’instructions​ plus longues⁤ pour accomplir le même travail. rePalm prend en charge les deux.

Plus tard, j’ai revisité le code et, malgré la complexité, j’ai trouvé un moyen d’utiliser l’instruction⁢ IT ⁤ sur Cortex-M3+. Cela a entraîné une refonte massive du code – en gros, en poussant le « code conditionnel » dans chaque ⁣fonction backend et ‌en s’attendant à ce qu’elle se conditionne ​comme elle le souhaite. Cela a produit un changement avec un diff⁣ de plus ⁢de 4000 lignes, mais cela ‌fonctionne très bien‍ et a entraîné une augmentation de‍ la vitesse !

Le Backend Cortex-M0

Pourquoi ⁣c’est un ‌défi

C’était un véritable défi, mais​ je voulais voir si je pouvais créer un backend fonctionnel pour Cortex-M0 dans mon JIT. Le Cortex-M0 exécute l’ensemble d’instructions ​ARMv6-m. Cela correspond essentiellement à Thumb-1, avec quelques ajouts mineurs. Pourquoi ‍cela⁣ est-il ⁢préoccupant ? Dans ​Thumb-1,​ la plupart des instructions ⁢n’ont accès qu’à la moitié des ⁣registres (r0..r7). Seules trois⁣ instructions ont ⁣accès aux registres supérieurs : CMP, MOV et ADD. Presque toutes les instructions Thumb-1 définissent⁣ toujours ⁢des indicateurs. ⁤De plus, ⁣il n’existe pas d’instructions de multiplication longue dans Thumb-1. Et il n’y a pas de mode de rotation RRX du tout. La confluence de tous⁣ ces problèmes rend la tentative d’une traduction instruction par instruction ‌de l’ARM vers Thumb-1 pratiquement ⁢impossible.

Les Fondamentaux

Les registres r0 à r3​ sont des registres de travail temporaires pour nous. Le registre r4 est l’endroit où nous stockons notre contexte⁤ (l’endroit où​ nous conserverons l’état supplémentaire). De ‌plus, pour des raisons de rapidité, nous aurons besoin d’un registre pour stocker le registre d’état virtuel. ‍Pourquoi en avons-nous besoin ? Parce que presque toutes nos instructions Thumb-1 modifient ​les indicateurs, tandis que le code ARM que‌ nous traduisons s’attend à ce que les ​indicateurs restent valides pendant de longues séquences⁣ d’instructions. Ainsi, notre total est de 6. Nous avons besoin de 6 registres. Ils⁤ doivent être des registres bas,⁢ car, comme nous l’avons discuté, les registres ‌supérieurs sont pratiquement inutiles dans Thumb-1.

Technologie : ⁣La rapidité de ‌PACE‌ est-elle suffisante ?

Les sauts indirects…

Malheureusement, l’émulation implique presque toujours de ⁤nombreux sauts‌ indirects. C’est en effet la méthode ⁢utilisée pour le décodage des instructions. L’architecture 68k, étant une architecture CISC avec ‍des‌ instructions de longueur ⁤variable, rend ‌cette étape ​de ​décodage complexe. L’émulateur‍ de PACE est clairement écrit à la ‍main ​en assembleur, avec quelques astuces. Il ⁢s’agit d’un code entièrement ⁢ARM,‍ et il est identique instruction par instruction ‍de PalmOS 5.0 à⁢ PalmOS ‌5.4. Bien que le code environnant ait changé, le cœur⁣ de l’émulateur est resté inchangé. C’est une bonne nouvelle, car cela signifie qu’il était déjà performant. Mon JIT gère correctement la traduction de PACE, comme en témoigne ​le fait que rePalm fonctionne sur ARMv7-M. Le principal problème réside dans le fait que chaque instruction émulée nécessite au moins un saut indirect (pour ⁤les instructions courantes), deux pour celles de fréquence moyenne, et jusqu’à trois pour certaines⁤ rares. En raison du fonctionnement de mon‍ JIT, chaque saut indirect qui n’est ⁤pas un retour de fonction ‍nécessite une exception ⁣(14 cycles⁣ à l’entrée,⁣ 12 à la sortie), un code d’assemblage supplémentaire (~30 ⁣cycles) et une⁣ recherche de hachage (~20 cycles). Ainsi, même si le code cible a été traduit, cela ajoute​ environ 70⁤ cycles à chaque saut indirect. Cela limite l’efficacité ⁤de l’émulateur 68k à un rapport ‌de 1/70 de ⁢la vitesse. Ce n’est pas idéal. En général, PACE fonctionne à environ 1/15 de ‌la vitesse ⁣du ‍code ‌natif, ce qui représente un ralentissement significatif. J’ai ​envisagé​ d’écrire ‌une meilleure traduction ‍spécifiquement pour PACE, mais cela s’avère assez complexe. En ‍effet, il n’existe pas de méthode simple et rapide pour traduire des instructions comme LDR R0, [R11, R1, LSL #2]; ADD⁤ PC, R11, R0. Il est impossible⁤ de savoir où ce saut ira, ou⁣ même si R11 pointe vers‍ un ‌emplacement immuable. Malheureusement, c’est exactement ce à quoi ressemble le dispatching de haut niveau ⁣de PACE.

Une ⁣solution spéciale pour ⁢un problème ‌particulier

J’avais déjà atteint mon objectif de faire fonctionner PalmOS sans modifications⁤ – PACE fonctionne avec mon JIT, et le système d’exploitation est utilisable et réactif. Cependant, je souhaitais​ une ⁢solution améliorée, car je considérais que⁤ PACE représentait un problème suffisamment unique pour justifier des efforts supplémentaires. L’émulateur⁣ de ⁣code dans PACE a un point⁣ d’entrée unique et n’appelle​ d’autres codes⁤ que dans dix cas précis : Line1010 (instructions commençant par 0xA), Line1111​ (instructions​ commençant par 0xF), TRAP0, TRAP8, TRAPF (OsCall), Division par zéro, Instruction illégale, Instruction ‍non implémentée, Bit de trace ⁢activé, et atteinte d’une valeur PC de 0xFFFFFFF0.⁣ Que faire alors ? J’ai ​développé un outil appelé « patchpace » qui prend un fichier​ PACE.prc de n’importe quel appareil PalmOS, l’analyse pour ‍localiser ces gestionnaires‌ dans le binaire, et identifie le cœur principal de l’émulateur. Il remplace‌ ensuite‌ ce cœur (sur ​place si l’espace le permet, sinon en l’ajoutant au ‌binaire) par le code que vous fournissez. Les ⁤adresses des ‌gestionnaires seront‍ insérées⁤ dans votre code aux offsets⁢ fournis⁢ par ⁣l’en-tête, et un saut vers votre code sera placé ⁣à ⁤l’endroit où se trouvait l’ancien cœur de l’émulateur. ⁢L’en-tête est très simple (voir « patchpace.c ») et inclut ⁤juste des offsets de demi-mots depuis le début du binaire jusqu’à l’entrée, et vers les ⁣sauts⁢ vers chacun des gestionnaires mentionnés sous ‌forme d’instructions BL ou BLX. Le seul paramètre pour⁢ l’émulateur est l’état. Il ‍est structuré comme suit : le premier mot est libre pour l’utilisation de l’émulateur,⁢ suivi de 8⁤ registres D, puis ⁢de 8 registres A, ensuite le PC, et enfin le SR. Aucun autre donnée n’est autorisée (PACE ⁤utilise des données après cela). Ce ​même état doit être transmis à tous les gestionnaires. Le⁢ gestionnaire TRAPF a également besoin que le mot suivant lui soit transmis (numéro OsCall).⁣ Oui, vous avez bien compris, cela vous permet ​d’apporter ‌votre propre émulateur 68k à la fête. N’importe quel​ émulateur 68k fera l’affaire, il n’a pas besoin de connaître quoi que ⁣ce soit sur PalmOS. Plutôt intéressant, non ?

N’importe ‍quel émulateur 68k…

Alors, où peut-on se ⁤procurer un émulateur 68k ? Eh bien, n’importe où ! J’ai écrit un émulateur simple en C pour tester cette idée, et cela ‌a bien fonctionné, mais pour ‍ce genre​ de projet, vous souhaitez utiliser de ​l’assembleur. J’ai pris l’émulateur de PACE comme ⁤guide de style ​et j’ai réalisé un travail ​considérable ⁣pour ‌produire ⁤un émulateur‌ 68k en thumb2. Il est beaucoup plus efficace que ce que PACE ⁤a ​jamais été. ⁤Cela est inclus dans le dossier « mkrom » sous le nom « PACE.0003.patch ». Comme mentionné précédemment, cela est entièrement optionnel et non requis. Cependant, cela⁣ améliore la vitesse brute du 68k d’environ 8,4 fois dans les cas typiques.

Technologie : Mais vous aviez promis du matériel…

Le matériel ‍a ses défauts

J’avais besoin d’une carte de développement pour expérimenter. La carte‍ de découverte STM32F429 semblait être un bon choix. Elle dispose de‍ 8⁢ Mo de RAM, ce qui est suffisant, de 2 Mo de flash, ce qui est​ bon, et d’un écran avec un écran tactile. En théorie, c’est parfait. Oh, si seulement j’avais su à quel⁤ point la ⁢réalité était imparfaite. En⁢ consultant le⁣ manuel de référence du STM32F429, il semble que‍ ce soit ⁤la puce⁣ idéale pour‍ ce projet. ‍Cependant, ST ne fait pas vraiment d’efforts⁢ pour‌ vous indiquer où‌ se trouvent les problèmes. La feuille d’errata est accablante. En ‍gros, si vous faites fonctionner le CPU à partir de la mémoire externe, placez la pile⁤ dans la ⁢mémoire externe, ⁣et que le FIFO‍ SDRAM est activé, les ⁤exceptions feront planter la puce ​(lecture incorrecte de l’adresse de vecteur). D’accord, je peux contourner cela⁢ – il suffit de désactiver⁤ le FIFO. Problème suivant : même ‍histoire, mais si ‌le FIFO est désactivé, parfois les écritures seront…

Défis et Solutions dans l’Ingénierie Inverse de PalmOS

Problèmes de RAM et de Gestion des Interruptions

Il est frustrant de constater que, malgré mes efforts pour transférer‍ mes⁣ données vers la RAM interne, des plantages continuent de se produire. Après avoir retiré rePalm et mis ‌en place un scénario de reproduction de⁣ 20 ​lignes, j’ai‍ découvert un problème non documenté dans ‍les notes de version de ST. Lorsque le registre PC pointe vers la RAM externe et que l’instruction WFI est exécutée pour attendre des interruptions en mode basse consommation, si‌ une interruption survient​ après plus de 60 ⁢ms, le processeur sélectionne un vecteur⁣ d’interruption aléatoire au⁣ lieu du‌ bon. Cela a nécessité de nombreuses nuits blanches à déchiffrer des plantages aléatoires dans les gestionnaires d’interruptions, qui ne devraient pas être actifs à ce moment-là. J’ai contourné ce‌ problème ⁣en évitant ‍d’utiliser⁢ WFI, ‍ce qui entraîne un gaspillage d’énergie,​ mais cela est acceptable pour le ⁢développement jusqu’à ce que je conçoive une carte avec un chip fonctionnel.

Problèmes d’Adresse‌ de RAM

Le STM32F429​ prend ⁢en charge deux banques de RAM, 0 et 1, ⁤avec la banque 0 commençant à 0xC0000000 et la‌ banque 1 à 0xD0000000. Cela pose un problème, car PalmOS exige que la RAM et la mémoire flash soient en dessous de 0x80000000. Heureusement, la banque 0 peut être⁤ remappée à 0x00000000. Cependant, la conception de⁢ la carte laisse à désirer, car elle ne dispose que⁣ d’une ‌seule ‍puce RAM, qui est logiquement la banque 0. En réalité, c’est⁤ la banque 1 qui est utilisée, et celle-ci ne peut pas être remappée. Cela rend la carte inutilisable pour démarrer PalmOS, car‌ la limite de​ 0x80000000 est rigide.

Pourquoi la Limite de 0x80000000 ?

PalmOS⁣ gère deux types ⁢de blocs‌ de ‍mémoire : les ⁣blocs mobiles et non ​mobiles. Cette distinction ⁣est essentielle pour un système d’exploitation sans unité de gestion de mémoire (MMU) ‍afin⁢ d’éviter ⁢une fragmentation excessive. Lorsqu’un bloc mobile n’est pas verrouillé, l’OS peut⁤ le déplacer, et il est référencé par un « handle ».​ On‍ peut ensuite le verrouiller pour obtenir ‌un pointeur, l’utiliser, puis le déverrouiller. ⁤La limite de 0x80000000 est cruciale, car PalmOS‌ utilise le bit supérieur d’un pointeur pour indiquer s’il s’agit ‌d’un handle ou d’un pointeur⁣ réel. Si le⁢ bit supérieur est activé, ⁤cela signifie ⁣un handle⁤ ; s’il est désactivé, c’est un pointeur. Ainsi, il est impossible d’avoir à la fois la RAM⁣ et la ROM au-dessus de 0x80000000.

Des Solutions Innovantes aux Problèmes de Conception

Étant donné que ⁤cette carte ⁣est destinée​ à un développement temporaire, pourquoi ne pas ⁣aller plus loin ? La distinction entre handle et pointeur n’est vérifiée qu’à quelques endroits. J’ai donc décidé de ⁤modifier ces vérifications ⁢pour inverser la condition, du moins ⁢temporairement. J’ai désassemblé et corrigé manuellement 58 emplacements, ‌principalement dans Boot, où se trouve le MemoryManager, et quelques-uns dans UI, car le code des champs de texte doit déterminer si un pointeur ⁢passé est un ​pointeur (non​ modifiable) ⁢ou un handle (modifiable). J’ai⁤ également effectué des modifications ⁣dans PACE, qui avait un SysTrap pour déterminer le type de ‌pointeur. Bien que cela ne soit plus‍ « PalmOS non‌ modifié », cela reste temporaire. Cependant, cela soulève une question : si⁤ nous inversions la condition, ⁤cela nécessiterait que la RAM et la ROM​ soient toutes deux au-dessus ⁣de ‍ 0x80000000. Mais la⁤ mémoire flash est à 0x08000000… Oups. Cela signifie que nous ne pouvons plus utiliser la mémoire flash.⁤ J’ai donc modifié la disposition de la RAM,‍ réservant 2 Mo à 0xD0600000 pour simuler la​ « ROM » et j’y⁣ copie la flash‌ au démarrage.⁤ Cela⁢ fonctionne !

Support de la Carte SD

Heureusement, j’avais déjà développé⁢ un pilote de slot pour PalmOS,‌ donc la⁤ création d’un pilote pour carte SD n’a pas été difficile. J’ai même réutilisé une partie du code⁤ source de PowerSDHC⁣ ! Le support des ​cartes SD est désormais opérationnel sur la carte de développement STM32F469. Sur la‌ carte ⁣STM32F429,‌ bien qu’elles soient également prises ⁣en charge, il faut les câbler soi-même, car la carte⁢ ne dispose pas de slot (CLK -> C12,‍ CMD -> D2, DAT_0 -> C8). En raison de la configuration de ⁣la carte, seul un bus d’un bit⁣ fonctionne, ce qui limite la vitesse à environ 4 Mbit/s sur la ‌STM32F429, tandis que ⁣sur ​la STM32F469, la vitesse atteint 37 Mbit/s. Des vitesses plus élevées pourraient être atteintes avec DMA, mais cela est suffisant pour le moment. En développant le support​ de la carte SD pour les puces STM32F4,⁢ j’ai⁤ découvert un bug matériel difficile à déboguer.‌ le bus SD permet à l’hôte d’arrêter l’horloge à tout moment, mais cela ​pose des problèmes lorsque la carte est occupée, car elle attend un signal d’horloge pour changer l’état de la ligne DAT_0. J’ai donc désactivé la fonction d’arrêt automatique de​ l’horloge après une semaine de débogage, ce qui a‌ nécessité une simple correction d’une ligne.‍ Le pilote de ​slot ⁤est disponible dans le répertoire « slot_driver_stm32 ».

Support du Port Série

Palm Inc a documenté⁤ la création d’un pilote ‍de port série pour PalmOS 4, avec deux types : les pilotes⁣ virtuels et ​les ⁢pilotes série. Les premiers ⁣étaient destinés‌ aux ports non câblés (comme le port Bluetooth ou infrarouge), tandis que les seconds étaient pour les⁤ ports câblés (comme le port série du socle). PalmOS⁢ 5 a fusionné ces deux types en un type⁢ « virtuel » unifié, mais cela n’a pas ‌été documenté. J’ai⁤ dû effectuer une ingénierie inverse prolongée ‍pour comprendre ⁢son⁤ fonctionnement. J’ai produit une idée fonctionnelle de ce système⁣ sur‌ PalmOS 5, que vous pouvez consulter dans le fichier d’inclusion « vdrvV5.h ». Ces informations suffisent pour‍ créer⁤ un pilote fonctionnel pour un port série, un port IrDA​ SIR ⁣et USB pour‌ les synchronisations.

La mise⁣ en‍ œuvre du port série‌ sur‍ le matériel STM32F4 a été un défi. Le matériel ne dispose que d’un seul tampon d’un octet, ce qui signifie qu’il faut utiliser le contrôle de flux matériel ⁤ou faire en sorte que l’interruption du⁢ port série⁢ soit de la ‌plus haute priorité pour éviter de perdre des données à des débits élevés. Cela n’était pas acceptable​ pour moi, ‌j’ai donc opté pour le⁢ DMA. Cela m’a permis d’écrire ma première bibliothèque PalmOS 5 pouvant être utilisée par d’autres bibliothèques.⁣ J’ai développé une bibliothèque DMA‍ pour les puces de la série STM32F4, disponible⁢ dans le répertoire « dma_driver_stm32 ». Cependant, le DMA nécessite de savoir combien d’octets⁣ vous attendez ⁣de recevoir, ce qui pose problème pour les données UART génériques. J’ai donc utilisé ‌une approche astucieuse :‌ le DMA peut nous interrompre lorsque la⁣ moitié d’un transfert ⁢est terminée, puis à nouveau lorsque tout‍ est terminé. Le DMA peut ‍être circulaire, ce qui nous permet de redémarrer au début une fois le transfert terminé. Cela⁢ nous rapproche de la solution idéale tant que les ⁣données continuent d’arriver.

Gestion des Interruptions et Réception de Données

Lorsqu’il s’agit de gérer les ⁢interruptions, il ​est essentiel de s’assurer que notre ⁣système peut traiter les données efficacement. Dans notre gestionnaire d’interruptions,⁤ il est⁣ crucial de vérifier ⁢la position ⁤actuelle ‌dans le ⁣tampon et de signaler les octets reçus depuis notre dernière vérification comme de nouvelles données. Cependant, un problème se pose si nous ne recevons qu’un seul octet. Cela représente moins de la moitié ‍d’un transfert, ce ⁤qui signifie qu’aucune interruption ne sera générée, et nous ne pourrons pas signaler cette donnée aux ⁣clients. Cette situation ‌est inacceptable.‍ Heureusement, le mode « détection IDLE » du UART STM32F4 résout‍ ce problème. Ce mode​ déclenche une‍ interruption si, après la réception d’un octet, quatre temps de bits‌ s’écoulent sans qu’un nouveau caractère ne commence. En intégrant cette interruption à notre code de gestion du tampon circulaire, nous ​pouvons recevoir des données à la⁤ vitesse à laquelle elles ⁢arrivent, peu importe leur taille. Mon pilote série, que vous ‍pouvez trouver dans le répertoire « uart_driver_stm32 », fonctionne parfaitement et‍ a même permis ‌une ‌synchronisation à⁢ chaud. Le ​support IrDA ​est également inclus, et tout fonctionne de manière fluide. Consultez l’album photo pour une démonstration vidéo !

Essayez-le‌ vous-même !

Pour ceux qui​ souhaitent expérimenter sur la carte de découverte ⁣STM32F429, le trou ⁣non peuplé de 0,1 pouce étiqueté « RX » est en réalité​ la sortie ⁢de transmission du STM32‌ (une étiquette quelque peu déroutante pour une broche de transmission). La broche B7 est celle de réception.​ En connectant un ‌adaptateur USB-série, vous pourrez ‌effectuer une synchronisation à⁤ chaud via le port série. Si vous optez pour un émetteur-récepteur IrDA SIR, vous obtiendrez également⁤ un fonctionnement ⁢IR. ⁢J’ai utilisé le transceiver MiniSIR2 de Novalog, Inc.,⁢ qui est le ⁣même que celui utilisé par la⁢ plupart des appareils Palm.

Support de Vibration et de LED

Le support de​ la vibration et des LED​ n’a jamais été documenté, car ce ‍sont des ‌fonctionnalités​ matérielles gérées par les‌ fournisseurs. ⁢Heureusement, j’avais déjà effectué une ​rétro-ingénierie de⁤ ces fonctionnalités⁣ lorsque j’ai ajouté le‍ support de vibration⁤ au T|X. Il s’avère que j’avais presque tout ‍compris à l’époque. Un peu plus de rétro-ingénierie a permis d’obtenir un résultat complet ⁢concernant l’API appropriée. Le fonctionnement des LED suit le même principe‌ que celui ⁣des vibreurs : une fonction « GetAttributes »⁣ et une fonction « SetAttributes ». Les paramètres ⁤réglables incluent⁢ le ‌motif, la vitesse, le délai ⁣entre les répétitions et le nombre de répétitions. Le système d’exploitation les utilise selon les⁢ besoins et ajoute automatiquement les paramètres ⁤ »Vibrer » ​et « LED »‍ au panneau de préférences « Sons et Alertes » si le matériel est pris​ en charge. Et rePalm prend désormais en charge les deux ! Le code est ⁤disponible ‌dans « halVibAndLed.c », n’hésitez pas à l’explorer à votre convenance.

Support Réseau (En Cours de Développement)

Débuts Difficiles

Mon objectif était ​d’ajouter un support réseau à rePalm. Plusieurs méthodes me venaient à l’esprit pour garantir ‍la compatibilité avec les applications existantes.‍ Une option ⁤serait de remplacer Net.lib par une version ayant une interface similaire, mais sous mon⁣ contrôle. Cela ⁢me permettrait de le connecter à n’importe quelle interface de mon choix, rendant tout cela magique. Cependant,‍ cette approche présente des inconvénients. Bien que de nombreuses parties de Net.lib soient documentées, d’autres ne le sont pas, rendant leur compréhension difficile. De plus, il est essentiel de faire fonctionner un PalmOS non modifié, ⁢et remplacer des bibliothèques ‍aléatoires compromet cette capacité. Cette méthode ne serait donc pas viable. ‍Une ⁤autre possibilité⁢ serait ⁣de créer une interface série fictive et de demander à PalmOS de ‍s’y connecter via SLIP ou PPP à une machine distante fictive. L’autre extrémité de ce port série pourrait être reliée à un thread ​communiquant avec notre véritable interface réseau. Bien que cela soit réalisable,‌ cela impliquerait des surcharges de codage et de décodage des trames PPP/SLIP, et ‍l’interface utilisateur serait‍ confuse. Trouver des moyens‍ de configurer l’interface serait également un‍ défi. Mais peut-être‌ existe-t-il une meilleure solution ?

Une Voie ⁣Difficile mais Prometteuse

Sur le plan conceptuel, une meilleure approche existe. ⁣Le ‌ Net.lib de PalmOS prend en charge des‌ interfaces réseau modulables⁤ (que j’appelle un pilote⁤ NetIF). On peut en trouver plusieurs sur tous les appareils PalmOS : PPP, SLIP, Boucle de retour. Certains autres modèles disposent également d’une ⁢interface pour le WiFi ou ⁤le réseau cellulaire. Il me suffit donc‍ de‍ produire un‍ pilote NetIF. Cela semble simple, n’est-ce pas ? En réalité, la réponse est un « non » ⁣retentissant ​! ‌Écrire des pilotes NetIF n’a jamais été documenté, et une interface réseau est beaucoup plus ‍complexe qu’un ⁣pilote de port série (qui était l’interface de pilote précédente de PalmOS que⁣ j’avais rétro-ingénierie). La rétro-ingénierie de cela⁤ s’avère être un défi considérable.

Apprendre de l’Histoire

J’ai commencé ‌par examiner⁢ certains appareils PalmOS 4.x et les pilotes NetIF SLIP/PPP/Boucle de retour. Pourquoi⁣ ? Comme je l’ai⁢ mentionné précédemment, dans l’architecture 68k, le compilateur a tendance‍ à laisser les noms de fonction ‍dans le binaire, sauf si cela est désactivé. Cela facilite grandement la rétro-ingénierie. Cependant, ⁤ne vous laissez‍ pas ⁤tromper, les noms de fonction ne sont pas si utiles en soi. Il faut encore deviner les ⁣formats de ⁣structure, les paramètres, etc. Ainsi, bien‍ que Net.lib et l’interface des ‍pilotes NetIF aient ‍changé entre PalmOS 4.x et 5.x, comprendre comment fonctionnaient les pilotes NetIF dans ⁣PalmOS 4.x⁤ fournirait des bases solides. Après⁤ quelques ​semaines d’analyse, je pensais avoir acquis cette⁣ connaissance. Je me suis alors demandé : « Y⁤ avait-il un appareil PalmOS 4.x avec WiFi ? »‌ En effet, il y en avait un. L’Alphasmart Dana ‌Wireless était équipé de WiFi. Maintenant ‍que⁤ je ⁣pensais avoir compris les bases du fonctionnement ⁤de⁢ ces pilotes NetIF, il était temps d’examiner un modèle‍ plus complexe, car PPP, ​SLIP et Boucle de​ retour sont très simples. Malheureusement, les développeurs d’Alphasmart savaient comment désactiver l’insertion des noms de fonction dans le binaire. Leur pilote WiFi était utile, mais il a fallu des semaines pour en tirer un sens. C’est à ce moment-là⁣ que​ j’ai réalisé‌ que Net.lib avait de⁢ nombreuses ⁢versions et que je devais examiner d’autres variantes. J’ai donc désassemblé chaque ⁤version de⁢ Net.lib existante⁤ pour observer l’évolution⁣ de l’interface⁣ des pilotes NetIF et de‍ Net.lib lui-même. J’ai ainsi⁤ étudié les versions de Palm V, Palm Vx, Palm m505 et‍ Dana. Les​ changements les plus intéressants se sont produits ‌avec‌ la ​version 9, où le support d’ARP et de ​DHCP a été intégré à Net.lib, alors qu’auparavant, chaque pilote NetIF nécessitant ces fonctionnalités intégrait sa propre logique.

Vers le Net.lib de PalmOS 5

Toutes ces découvertes étaient intéressantes, mais mon objectif n’était pas de comprendre comment fonctionnaient les‌ pilotes NetIF dans PalmOS 4.x. Il était temps de passer à la rétro-ingénierie de la⁣ manière dont PalmOS 5.x procédait. J’ai récupéré une copie de Net.lib du T|T3 et⁤ commencé à tracer ses fonctions, en les associant à leurs ⁣équivalents⁢ de⁣ PalmOS 4.x. Après quelques semaines supplémentaires, j’avais plus‌ ou moins compris le fonctionnement ⁣de Net.lib dans PalmOS 5.x.

Une Découverte Importante

Au cours de mes recherches, j’ai découvert‌ un véritable bug‌ : un problème ⁤de​ « use-after-free » dans arp_close().

NETLIB_T3:0001F580 ‍ ‍ ⁤ CMP R4, #0 ; ‌La liste chaînée est-elle ⁢vide ?
NETLIB_T3:0001F584⁤ ⁣ BEQ ‍ ⁢ ​ loc_1F5A4 ‍ ⁢; Si oui,‌ il suffit de⁤ sauter cette partie
NETLIB_T3:0001F588 ​ B ⁣ ⁢ ‍ ⁤ ⁣loc_1F590 ;⁣ Sinon, libérer un​ par un
NETLIB_T3:0001F58C
NETLIB_T3:0001F58C loc_1F58C:
NETLIB_T3:0001F58C⁣ ⁣ BEQ⁢ ​ loc_1F598

Exploration ⁣des ⁢pilotes⁢ NetIF de PalmOS

Introduction à l’ingénierie inverse

J’ai commencé à examiner les pilotes NetIF SLIP/PPP/Loopback de PalmOS 5.x pour comprendre les ‌modifications apportées par rapport à PalmOS 4.x. Je pensais que la ‍logique de base n’avait⁣ pas beaucoup évolué, donc les différences que je pourrais observer‍ pourraient indiquer des changements dans ​la structure de Net.lib et NetIF entre les deux versions. En réalité, peu de choses avaient changé. Les structures ‍avaient été réalignées ​et quelques valeurs d’attributs modifiées, mais dans l’ensemble, la similarité était frappante. À ce stade, je me suis félicité et ‍j’ai décidé de créer mon ​propre pilote NetIF pour tester mes connaissances.

Une réalité plus‌ complexe

Cette satisfaction n’a pas duré longtemps. En consultant mes notes, j’avais marqué certains éléments que je pensais insignifiants comme « à ⁣revoir‍ plus tard ». Il s’est avéré qu’ils n’étaient pas du tout négligeables. Par exemple, le ‌retour d’appel du DHCP vers le pilote NetIF pour l’informer de l’état du DHCP n’était pas‌ simplement informatif, ⁢comme je l’avais supposé. En fait, une‌ quantité​ importante de​ logique‌ devait être intégrée⁤ à ce processus. Cette logique interagissait avec la⁣ structure DhcpState, dont une partie m’était restée obscure,​ car je pensais qu’elle‍ était opaque pour le pilote NetIF. Je me suis donc⁣ replongé dans IDA ⁤pour approfondir ⁣mes recherches. J’ai réalisé qu’il me fallait une compréhension⁢ bien‍ plus approfondie du DHCP et de l’ARP. Après avoir consacré plusieurs heures à‌ lire les ​RFC sur le DHCP et l’ARP, je suis retourné au code désassemblé, et⁣ tout a commencé à prendre sens. Pour résumer, il m’a fallu ‌encore ⁢trois semaines​ pour documenter‌ chaque structure et fonction ⁣utilisée par le ‍code ARP et DHCP.

Approfondissement de l’ingénierie inverse

Il restait une dernière étape. Lorsque ‌le ⁣pilote NetIF se lance, ‍il ⁤doit afficher une interface utilisateur et interagir ‍avec Net.lib à différents ‌moments. Les divers pilotes NetIF que j’ai analysés le faisaient de manières très variées, ce qui m’a laissé dans l’incertitude quant à la méthode appropriée. J’ai donc⁤ consulté mon archive de ROM PalmOS et développé⁣ un outil pour‍ identifier tous les fichiers de type neti (les pilotes NetIF portent⁢ ce type), en excluant ceux qui étaient PPP,⁣ SLIP ou Loopback, et‌ en copiant le ⁤reste dans un dossier après ‍avoir éliminé les doublons. ‌J’ai ensuite désassemblé tous ces fichiers,‌ produisant ⁢des diagrammes et des ‍notes‌ sur ⁣la manière‍ dont chacun se lançait et se fermait, où⁢ l’interface utilisateur était affichée ou ​masquée, et à ⁤quel moment chaque ‍étape était réalisée. En procédant ⁤ainsi, j’ai découvert quelques journaux dans ⁣certains de ces pilotes, ce qui m’a permis de renommer mes⁤ propres valeurs et structures avec des noms plus appropriés, inspirés des déclarations de​ journalisation des développeurs de ‌ces pilotes. J’ai ainsi​ désassemblé : le « CFEtherDriver » de Sony ⁣pour l’UX50, le pilote WiFi de Hagiwara‌ « HNTMSW_neti », le « WLAN ​NetIF »​ de⁤ Janam pour l’XP30, le « CFEtherDriver » de Sony pour ‍le TH55, le « PxaWiFi » de PalmOne pour le Tungsten C, le « WiFiLib » de PalmOne pour le TX, et le « WiFiLib » de PalmOne pour leur‌ carte SD WiFi. Cela ‍a été un travail considérable ! l’interface NetIF que j’ai rétro-ingénierie ​est documentée ⁤dans « netIfaceV5.h », et‍ je pense qu’il est désormais possible d’écrire un pilote NetIF fonctionnel en utilisant ‍cette documentation.

Vous pourriez vous demander : « As-tu déjà testé cela ? ». Non, je suis encore en train de‍ rédiger mon pilote NetIF, alors restez à l’écoute…

Support de densité 1.5

Les bases de​ la densité

technologie Bad rendered‍ PalmOS

Depuis ‌la version 4.2, PalmOS prend en charge plusieurs densités ⁢d’écran. Cela‌ signifie qu’un appareil peut avoir un écran de ⁤même taille, mais avec plus ⁣de pixels, permettant ainsi de voir les éléments ​affichés à la même taille, mais avec plus de détails.‍ Bien que Sony ait proposé des écrans haute résolution avant ⁣Palm, et HandEra avant les deux, la solution de Palm a été​ la première à être intégrée à l’échelle du système d’exploitation, ce qui a été adopté par PalmOS ​5. Le principe est simple⁤ : chaque Bitmap/Fenêtre/Police, etc., possède un système de coordonnées associé, et toutes les opérations s’appuient​ sur cela⁣ pour déterminer comment mettre à l’échelle les éléments. Les ‍écrans 160×160 étaient qualifiés de‍ 72ppi (sans ⁢rapport avec les points ou‌ les pouces réels), tandis que les ⁣nouveaux écrans ⁤320×320 étaient à 144ppi (double densité).​ Cela simplifiait⁣ la vie : lorsque l’image ou la‌ police de la bonne⁣ densité était ​manquante, il était possible ​de doubler les pixels de la version basse ‍résolution.⁢ L’inverse était également vrai.⁤ Les coordonnées du stylet devaient également être ajustées, car le développeur pouvait désormais demander à ‍travailler dans un système de coordonnées‍ particulier, ce qui‍ nécessitait une adaptation de l’ensemble de l’API système.

Comment cela a-t-il été mis en œuvre ? Plusieurs systèmes de coordonnées sont toujours en jeu : natif (ce que l’affichage est), standard (utilisé‌ pour la mise en page de l’interface utilisateur) et actif (défini par l’utilisateur via WinSetCordinateSystem). Ainsi, à tout ‍moment, il existe six facteurs d’échelle pour convertir ⁢d’un système à un autre. PalmOS 5.0 n’en utilisait qu’un, ce⁤ qui​ était désordonné et ne sera pas approfondi ici.⁣ Disons simplement que cette solution n’a pas perduré. PalmOS 5.2 et les versions ultérieures ⁢utilisent quatre facteurs d’échelle, représentant des transformations bidirectionnelles entre actif et natif, et natif et standard. Pourquoi pas ​la troisième paire ? ⁣Elle est utilisée de manière suffisamment rare pour que deux ​transformations soient acceptables.‌ Étant donné ‌que les calculs ‍en virgule flottante sont‌ lents‍ sur ARMv5, des nombres⁣ à virgule fixe sont utilisés. Ici, il existe une différence entre PalmOS 5.2‌ et PalmOS 5.4. La première utilise des​ nombres à virgule fixe de 16 bits au format 10.6, tandis que la seconde utilise des nombres de 32 bits au ⁢format 16.16. Je vous laisse le soin de ⁤vous renseigner sur les nombres à virgule fixe, ⁣mais l’essentiel est que ​le nombre de bits de fraction ⁣limite la précision du nombre lui-même et les calculs que l’on peut effectuer⁢ avec. Pour des puissances de deux précises, il n’est ‌pas nécessaire d’avoir ‌autant de bits, donc tant​ qu’il n’y avait ⁣que ​des écrans 72ppi et 144ppi, le format 10.6 était⁤ suffisant, avec des⁣ facteurs d’échelle toujours à 0x20 (x0.5), 0x40 (x1.0) et 0x80 (x2.0). PalmOS 5.4 a ajouté le support ​de la densité un et demi en raison de l’abondance d’écrans 320×240 bon marché à l’époque.​ Cette nouvelle​ résolution⁤ était spécifiée à 108ppi, soit précisément 1,5 fois ⁤la résolution standard. Techniquement, tout ce qui était ‍en PalmOS 5.2 fonctionnera tel quel, et si vous donnez à PalmOS 5.2 un écran de cette résolution, cela fonctionnera⁢ également.

Comprendre les Défis de PalmOS et les Solutions Innovantes

Lorsqu’on examine l’affichage sur un écran, il est évident que cela fonctionne, bien que de manière peu esthétique. À droite, vous⁣ pouvez voir un exemple​ de ce à quoi cela ⁤ressemble. Bien que cela ne⁣ soit pas attrayant, le système ne plante pas et les ‌fonctionnalités de⁣ base fonctionnent comme prévu. Mais pourquoi cet affichage est-il si dégradé ? La réponse réside ⁢dans les facteurs ‍d’échelle. Analysons les facteurs d’échelle nécessaires.

Les Limitations de⁤ PalmOS

Tout d’abord, il est important de noter que PalmOS ne peut pas⁢ effectuer de mise à l’échelle entre 108 et 144 ppi pour les⁢ bitmaps ou les polices. Par conséquent, ces facteurs d’échelle ne sont pas requis. Cependant, rePalm, dans un cas particulier, ​peut dessiner⁣ des bitmaps ‍de 144 ppi sur un écran de‍ 108 ppi, mais uniquement si aucun bitmap de 72‌ ppi ou 108 ppi n’est disponible. Les nouveaux facteurs d’échelle introduits se situent entre la⁣ densité standard et 1,5. ⁢Pour passer de la densité standard à 108 ppi, le facteur d’échelle est de 1,5, ce qui peut être ‍représenté sous la forme 0x60 dans le format⁤ à virgule fixe 10.6. Cela‌ fonctionne parfaitement, mais le ‌passage de 108 ppi à 72 ppi pose⁢ problème, car le facteur‌ d’échelle est de 2/3, ce⁤ qui n’est pas représentable de ⁣manière exacte en binaire, peu importe la précision des bits.

La règle simple avec les mathématiques à virgule fixe ⁣est que lorsque ‌vos nombres ne sont pas représentables de manière exacte, les erreurs d’arrondi ⁣s’accumulent. Pour le ‌format 10.6, la⁣ plus petite unité (LSB) est ⁣de‌ 1/64, ‍donc dès que nous‍ travaillons avec des ⁢nombres ‍supérieurs ⁤à 64, les erreurs d’arrondi dépassent une unité. ‍Cela pose un problème, car PalmOS utilise fréquemment ⁣des nombres supérieurs ​à 64 dans l’interface utilisateur. Par exemple, la largeur standard de l’écran est de 160​ pixels. Ces⁢ erreurs d’arrondi ​accumulées sont‍ visibles dans les captures​ d’écran. La prise en charge officielle de la densité 108‌ ppi a été introduite dans PalmOS 5.4. Que s’est-il passé pour corriger cela ? Ils​ ont opté ‍pour‌ le format 16.16,​ où la LSB ⁣est de⁢ 1/65536, permettant ainsi un arrondi correct pour les nombres jusqu’à​ 65536, ce ⁣qui est suffisant puisque toute l’interface ⁣utilisateur de PalmOS utilise des nombres de 16 bits pour les coordonnées.

Les Problèmes de PalmOS 5.4

Pourquoi est-ce important ? PalmOS 5.4 présente d’autres caractéristiques qui⁢ le rendent peu attrayant pour rePalm, notamment l’utilisation ⁤obligatoire de NVFS. Mon objectif était ‌de faire fonctionner ⁤PalmOS 5.2 tout en intégrant la prise en charge de la densité 1,5, car les écrans 320×240 sont ​encore très abordables, ‍comme celui de ma carte de développement STM32F427. Il n’est pas possible de simplement transférer Boot.prc de‍ PalmOS 5.4, car cela impliquerait également NVFS. Que faire alors ? J’ai ⁣décidé de dresser un​ inventaire de chaque partie du système d’exploitation utilisant ces valeurs d’échelle, qui sont dissimulées dans la structure « Window », ⁤principalement dans Boot. Cependant, d’autres ⁤problèmes⁤ peuvent ‌survenir. Par exemple, dans certaines ‍parties de l’interface utilisateur, des séquences comme BmpGetDensity(WinGetBitmap(WinGetDisplayWindow())) peuvent⁢ être observées. Cela peut⁢ poser des problèmes, surtout si des calculs sont effectués avec ces valeurs.

La Solution : Écrire une Extension OEM

Corriger autant d’endroits est faisable, mais que se passe-t-il si je décide​ d’utiliser le ⁢Boot d’un autre appareil‌ à l’avenir ​? Ce ‍n’était pas ‌une solution viable. ‍J’ai donc choisi d’écrire une extension‍ OEM, un module que le système d’exploitation chargera au démarrage, pour résoudre ce problème. Mais comment procéder ‍? ⁢Étant donné que la ROM est en lecture seule et qu’il ⁢n’y a‌ pas d’UMM pour mapper ⁤une page sur les ⁣zones à corriger, comment faire ? Chaque problème se trouve logiquement dans une fonction, et ‌chaque fonction est parfois appelée, que⁤ ce‌ soit par un minuteur, une⁤ notification, un ‍thread ou une action de l’utilisateur. Heureusement, PalmOS n’attend que des travaux d’interface ​utilisateur du thread d’interface, donc toutes ces fonctions étaient appelées uniquement par⁣ des fonctions orientées utilisateur. Malheureusement, certaines étaient profondément enfouies. J’ai commencé à écrire des fonctions de remplacement, en m’inspirant de​ ce que⁢ faisait le Boot de PalmOS 5.4. ‍Pour la plupart⁢ des fonctions, j’ai écrit des correctifs complets, remplaçant ⁢entièrement la fonction originale dans ⁢la table de dispatch, ⁣sans jamais rappeler l’original. J’ai ainsi développé 73 correctifs, incluant des fonctions telles que ​FntBaseLine, FntCharHeight, FntLineHeight, et bien d’autres.

Améliorations de l’Interface Utilisateur dans⁢ PalmOS

Dans le cadre de l’optimisation⁢ de​ l’interface utilisateur​ de PalmOS, certaines fonctions se sont révélées trop complexes pour être remplacées intégralement. Prenons l’exemple de PrvDrawControl, une fonction essentielle de CtlDrawControl, ⁣qui est également ​utilisée ⁢dans divers contextes, notamment la gestion des événements pour les contrôles. Que faire alors ? Bien que je puisse remplacer tous les appelants, tels que FrmHandleEvent et CtlDrawControl, cela ne résout pas le‍ problème, car PrvDrawControl présente des défauts et⁤ est d’une complexité énorme. Après une analyse ⁢minutieuse,‌ j’ai constaté qu’elle ne se préoccupait réellement de la densité que dans​ un cas⁤ particulier,‍ lors du dessin d’un cadre de​ type 0x4004. ​Dans ce cas, elle modifie le système de coordonnées⁣ pour‌ le rendre⁢ natif, dessine le cadre manuellement, puis réinitialise le système de‍ coordonnées. J’ai donc mis en⁢ place un ⁢indicateur global avant⁣ de l’appeler ​si le ​type de cadre demandé était celui-là, et ⁤la fonction de dessin de cadre,⁣ que j’avais déjà ‌réécrite (WinDrawRectangleFrame), détecte ce drapeau et exécute alors cette opération spéciale. La même approche a été appliquée pour l’effacement du ⁣cadre de type 0x4004. Les résultats ? Cela a⁢ fonctionné !

technologie⁤ Bien rendu PalmOS

Gestion des Titres de Fenêtres

Un ⁣autre cas⁣ complexe​ restait‌ à traiter : le ⁢dessin d’un titre⁤ de fenêtre. Cela était profondément intégré dans FrmDrawForm, car un titre est techniquement ⁣un type d’objet cadre. Pour intercepter cela sans réécrire la fonction entière,⁣ j’ai converti un objet titre en un⁢ type spécial‌ d’objet liste et sauvegardé l’objet original dans mes ​variables globales. Pourquoi ‌une liste ? FrmDrawForm appelle LstDrawList sur un objet liste sans examiner son contenu. J’ai donc intercepté LstDrawList, vérifié ⁤notre pointeur magique, et⁤ si c’était le cas,⁢ dessiné le titre, sinon laissé la fonction ‍originale LstDrawList s’exécuter.⁤ À la sortie de​ FrmDrawForm, tout cela est ‍annulé. Pour⁤ les fonctions de réglage de titre de formulaire, je les ai remplacées, car elles redessinent le titre manuellement, et j’avais déjà​ écrit une fonction ‍de dessin de titre. Il restait‌ une⁤ petite chose à régler : l’icône (i) sur les formulaires associés à l’aide. Elle était mal rendue​ lorsqu’on appuyait dessus. Ma fonction de dessin de⁤ titre la rendait parfaitement, mais la réponse ⁣au tap était gérée par ⁢ FrmHandleEvent,⁤ une autre fonction que je ne souhaitais pas remplacer. En examinant cela, j’ai remarqué que la gestion ⁢des ⁣taps sur l’icône ⁤d’aide ⁤(i) se faisait assez tôt. J’ai⁣ donc dupliqué ⁢cette logique (et certaines qui la précédaient) dans mon correctif pour FrmHandleEvent et n’ai pas laissé‌ la fonction originale traiter ​cet événement. Cela‌ a parfaitement fonctionné !‍ Ainsi, nous avons quatre correctifs partiels supplémentaires :‌ LstDrawList, FrmDrawForm, ​ FrmHandleEvent, et CtlDrawControl.

Optimisation de la Densité d’Affichage

Il restait encore‍ une tâche à accomplir⁤ : assurer un support adéquat pour ⁣la fonctionnalité de densité 1.5, telle que définie⁤ par le SDK. J’ai donc modifié le‍ DAL pour ⁤me permettre⁤ de ⁤corriger ‌des fonctions qui n’existent pas du ⁣tout dans la ‌version actuelle ‍du‌ système d’exploitation, car ⁣certaines nouvelles avaient été ajoutées‌ après la version 5.2 pour faire fonctionner cette fonctionnalité : WinGetScalingMode et WinSetScalingMode. ⁢Ensuite, j’ai adapté ​le gestionnaire de dispatch 68k de ‌ PACE pour sysTrapHighDensityDispatch afin de ​gérer les nouveaux sélecteurs de trap 68K‍ HDSelectorWinSetScalingMode et HDSelectorWinGetScalingMode, laissant le reste des anciens sélecteurs être gérés par PACE ‍ comme auparavant. J’ai également acquis des ‌polices 108ppi et écrit du code pour⁣ remplacer⁣ les polices système par celles-ci, ainsi ⁤que des images système 108ppi (comme les icônes d’alerte) et fait en sorte ‍que mon extension les place aux bons endroits.

Le résultat ? Le système a fière allure ! Il reste encore des éléments à corriger, techniquement, et « main.c » dans⁢ le dossier « Fix1.5DD » contient un commentaire les listant, mais ce sont tous des ‍détails mineurs et le système est déjà très esthétique. L’extension « Fix1.5DD » ‌fait⁢ partie⁢ du code ‌source que je ‌publie ‍avec rePalm,‍ et vous pouvez voir ​la capture d’écran de comparaison « après » juste au-dessus à droite. Cela représente environ 4000 lignes de code, réparties sur 77 correctifs et un peu de logique d’installation.

Support des ⁣Services de Zone d’Entrée Dynamique‍ et de Gestion des Entrées au‍ Stylet

Les Fondamentaux de DIA/PINS

Initialement, PalmOS ne prenait en charge que les ‍écrans carrés.⁤ Quelques fabricants (Handera, Sony) ont produit des écrans non carrés, mais cela n’était pas standardisé. Sony a fait des progrès significatifs avec ses appareils Sony Clie 320×480.‌ Cependant, leur API était exclusive à Sony⁢ et n’a ‌pas été adoptée par d’autres. Lorsque PalmOS 5.2 a ajouté le support des écrans non carrés, Palm a créé une API appelée PINS⁤ (ou DIA ou AIA). Bien qu’elle ne soit pas aussi performante​ que celle de Sony, elle était officielle, ce qui a conduit‍ tout le monde ⁣à y migrer. Les⁣ appareils Sony ⁣ultérieurs ont également dû la prendre en​ charge. Pourquoi était-elle moins efficace ? L’API de Sony était simple : réduire la zone d’entrée dynamique ‍ou la rétablir. Activer ou désactiver ⁤le bouton correspondant. Facile. L’API ⁤de Palm, quant ‌à elle, essaie d’être intelligente, avec des politiques par formulaire et une multitude de complexités. ⁤Elle propose également des fonctionnalités‍ simples‍ : ⁣faire descendre ou remonter la zone, ou activer ou désactiver le bouton. Cependant,⁢ tous ces paramètres ⁣sont aléatoirement modifiés ou effacés⁣ chaque fois⁣ qu’un nouveau formulaire apparaît à l’écran, ce qui rend l’utilisation très pénible ! Quoi​ qu’il en soit, c’est l’API publique. Comment cela fonctionne-t-il ? Dans PalmOS 5.4, tout cela fait partie intégrante du système d’exploitation, ‌intégré dans Boot.

Fonctionnement avant Garnet

Comme je l’ai mentionné, je visais PalmOS 5.2. À‌ cette époque, ce n’était pas intégré⁢ au système d’exploitation, mais représentait une extension. Le DAL présente au système un écran brut de⁣ la résolution réelle (généralement 320×480) ‍et l’extension masque la zone inférieure des applications tout en dessinant la zone d’entrée dynamique dessus. Cela nécessite d’intercepter certains appels du système d’exploitation, tels que FrmDrawForm (pour ‌appliquer la nouvelle politique),​ FrmSetActiveForm ⁤ (pour appliquer la politique aux formulaires déjà ⁣dessinés), SysHandleEvent (pour gérer les événements dans la ​zone d’entrée dynamique), et UIReset (pour réinitialiser les paramètres ​par défaut lors du changement d’application). Nous souhaitons également être informés de certains événements, comme le changement de profondeur⁤ de couleur de⁤ l’écran. Lorsque cela se produit, nous devons peut-être redessiner la zone d’entrée. Voilà l’essentiel. Cependant, il existe de nombreux détails‍ petits mais significatifs.

Les Complexités de l’Écriture ⁣d’une Implémentation ⁣DIA

Avant de me lancer dans l’écriture de ma propre implémentation DIA, j’ai‌ testé toutes les existantes pour voir si elles supportaient des résolutions autres que 320×480. Je ne voulais pas écrire du code ⁤inutile,​ après⁣ tout. Aucune d’entre ⁢elles ne fonctionnait correctement.⁤ Même des résolutions simples comme 160×240 (un simple redimensionnement 2x) étaient défaillantes. Les écrans avec des rapports d’aspect différents, comme les courants 240×320 et 160×220, étaient ‌encore plus problématiques. ⁢Pourquoi ?​ Je suppose que ⁢personne n’écrit de code générique. Il est plus simple de bricoler des solutions « pour l’instant » sans plan pour « plus tard ». J’ai donc décidé d’écrire une implémentation DIA capable de supporter presque‌ toutes les résolutions.

Lorsque la zone d’entrée dynamique est réduite, une barre d’état ⁤s’affiche. ⁤Elle montre de petites icônes comme le bouton d’accueil et le bouton de⁣ menu, ainsi que‍ le bouton pour révéler la zone d’entrée. J’ai essayé de rendre tout aussi générique que​ possible. Pour chaque résolution ⁤d’écran, il est ‌possible de créer ‍un skin. Un skin ⁢est un ensemble de graphiques représentant la ⁤zone d’entrée dynamique, ainsi que quelques entiers décrivant ‌les zones et leur fonctionnement ​(quels codes‍ de touches ils envoient, ⁤ce qu’ils font). Les spécificités sont décrites dans le code, les commentaires et les exemples (3 ⁤skins conçus ​pour ressembler aux interfaces de Sony). Ils définissent également une zone de « notification ». Toute application​ peut y‌ ajouter ​des icônes. Même ‍les‍ applications 68k normales peuvent le faire ! J’inclus également un exemple à ce sujet. L’horloge ​que vous voyez dans la barre d’état est en fait une application 68k appelée « NotifGeneral », et son code source est fourni dans le cadre de rePalm.

Introduction au support audio sur PalmOS

Depuis la version 1.0 de PalmOS, un support audio basique a été intégré, permettant la production de sons simples via un haut-parleur piézoélectrique. Cela se traduit par des bips élémentaires. L’API officielle permet de jouer un fichier MIDI (un canal, uniquement des ondes​ carrées), de générer un⁢ ton à⁤ un volume et une amplitude⁢ spécifiés (en arrière-plan ou au premier plan), et d’arrêter ce ton. Avec PalmOS ⁢5.0, ‌l’API de bas niveau qui soutient cette API audio simple est presque identique à l’API officielle de⁣ haut niveau. La ​fonction HALSoundPlay est‍ utilisée pour ⁤démarrer un ton pendant une durée​ déterminée. Ce ton fonctionne en arrière-plan, et la fonction retourne immédiatement.⁤ Si‍ un autre ton était ⁣déjà en cours, il ‍est remplacé par le nouveau. Une valeur​ de durée ‌négative signifie que le ​ton ne s’arrêtera jamais automatiquement. La fonction HALSoundOff permet d’arrêter‌ un ⁢ton en cours de lecture, s’il y en a un. La fonction HALPlaySmf joue une mélodie MIDI, mais son utilisation est optionnelle. ‌Si le DAL renvoie une erreur, Boot interprétera ⁣le fichier MIDI‍ et effectuera une série d’appels⁤ à HALSoundPlay. Cela signifie que, sauf si vous disposez d’un matériel capable de jouer des MIDI de manière plus efficace que des ondes carrées à un canal, ‌il n’est pas judicieux d’implémenter HALPlaySmf dans votre DAL.

Support audio échantillonné sur PalmOS

À‍ l’époque de la sortie de PalmOS 5.0, une API pour le son échantillonné a été introduite. Bien qu’elle ⁤ne nécessite pas obligatoirement PalmOS 5.0, il n’existe⁣ pas de dispositifs Palm OS⁣ 4 qui l’implémentent. Des ‌API audio spécifiques‌ aux fournisseurs avaient été présentes dans les versions antérieures de PalmOS, ⁢mais elles étaient non standard et dépendaient généralement de puces ⁢d’accélération matérielle personnalisées, car le processeur 68k n’est pas‌ assez rapide pour décoder des formats audio complexes. L’API de son échantillonné⁣ est plus complexe que l’API‍ de son simple, mais‌ elle peut être expliquée par le concept de flux. On peut ‍créer un flux‌ d’entrée ou de⁣ sortie, définir le volume et le panoramique, et recevoir une notification⁤ lorsque des données sont disponibles (entrée) ou nécessaires (sortie). Pour les flux de sortie, le système est censé les mixer ensemble, permettant ainsi ​à plusieurs flux audio de jouer simultanément.

Les défis de l’audio et la solution de PalmOS

Le mélange audio est​ un processus complexe. Assurer une bonne ⁢qualité est⁢ encore‍ plus difficile, et le faire rapidement ​l’est encore ‍davantage. Pourquoi cela ? Le matériel audio ne peut sortir qu’un seul⁢ flux, ce qui nécessite​ de mixer plusieurs ⁢flux en un seul. Ce mélange peut impliquer une conversion de format, par⁢ exemple si le ⁣matériel nécessite des‌ échantillons signés de ‌16 bits en format little-endian et qu’un des flux ⁢est en format flottant. De plus, le mélange peut nécessiter un ‍rééchantillonnage. Si, par ⁤exemple, le matériel fonctionne ‌à 48 ⁣000 ‍échantillons par ​seconde ‍et qu’un client demande à jouer un flux à 44 100 échantillons par seconde, il faut générer plus d’échantillons que ceux fournis. Cela peut sembler simple avec de grands tampons, mais cela entraîne une latence ‍importante. En audio, il est crucial de travailler avec​ des tampons relativement ⁢petits, car les⁢ utilisateurs remarqueront si les ⁢échantillons audio sont livrés en retard.

Comment rePalm gère ‍le mélange audio

Mon objectif avec rePalm était de produire une qualité audio optimale tout en prenant en charge⁢ tous les‌ formats que l’API PalmOS prétendait supporter. En réalité, j’ai⁢ même pris ⁤en charge davantage de formats : entiers⁤ signés et non signés de 8, 16 et 32 bits, ainsi que des échantillons en virgule flottante simple précision dans n’importe‌ quel ‌ordre d’octets. Pour les taux d’échantillonnage, le mélangeur‍ de⁤ rePalm prend en charge : 8 000, 11 025,‌ 16 000, 22‌ 050, 24 000, 32 000, 44 100 et⁤ 48 000 échantillons par‍ seconde. Le format utilisé par le matériel de ‌sortie est déterminé par le pilote matériel à l’exécution dans rePalm. Le matériel mono et stéréo est pris ⁣en charge,​ ainsi que tous les​ taux d’échantillonnage⁣ et formats d’échantillons pour la ⁢sortie matérielle native.

Gestion des tampons audio

La méthode initiale consistait à attribuer à chaque canal un⁤ tampon circulaire unique que le client remplirait et que le mélangeur lirait. Cependant, cela ⁣s’est avéré trop‌ complexe à ​gérer en langage d’assemblage. La solution ‌finale que j’ai⁤ adoptée était en réalité plus simple ‍à gérer. Chaque flux dispose de plusieurs tampons (la profondeur du tampon est actuellement ‍définie à quatre), et une fois qu’un tampon ‌est complètement rempli, ⁤il est envoyé ​au mélangeur. Si aucun tampon n’est⁤ disponible, le client est bloqué, comme l’exige PalmOS. Si le mélangeur n’a pas de tampons pour un flux, ce dernier ⁤ne sera pas joué, conformément à⁣ l’API de⁤ PalmOS. Ce⁢ système ‍est facile à gérer ⁤des deux côtés, car le mélangeur n’a jamais à traiter des tampons⁣ partiellement‍ remplis.

Il est important de⁢ noter que le support​ de l’API de son ⁢échantillonné ne ‌dispense​ pas de prendre en charge les fonctions de⁤ son simple. rePalm crée un flux sonore pour le support du ⁣son simple​ et l’utilise pour jouer les tons requis, générés‌ à partir d’une ⁣onde sinusoïdale interpolée au moment de la demande. Pour faciliter cela⁤ sans avoir à gérer des rappels, le mélangeur⁣ prend en charge​ des ⁣canaux « bouclés ». Cela signifie ⁤qu’une fois le tampon de données rempli, ‌il est joué en boucle jusqu’à ⁤ce qu’il ‌soit arrêté.

Introduction à la gestion audio de rePalm

rePalm a choisi de ne pas reproduire de tonalités en dessous de 20Hz, ​ce ‍qui me semble tout à fait acceptable.

Assemblage et ‌mixage audio

La question du rééchantillonnage, du mixage et de la ⁢conversion de format​ était un défi majeur. L’approche simpliste consistant à prélever un échantillon de chaque flux, à le mélanger dans le flux de sortie,‌ puis à répéter le processus pour le flux ⁢suivant s’est⁢ révélée trop lente en raison des constantes « commutations » nécessaires selon les types ‍et‍ les taux d’échantillonnage. Le rééchantillonnage devient également complexe s’il doit être effectué avec une qualité acceptable. Que fait donc ⁤le DAL de rePalm ? Pour le rééchantillonnage,‌ un grand nombre⁤ de tables sont utilisées.⁢ Pour l’upsampling, une table indique comment interpoler linéairement entre les⁢ échantillons d’entrée pour produire ‍des‍ échantillons de ⁣sortie. Une table soigneusement ajustée existe pour chaque paire de fréquences. Pour le ‍downsampling, une table précise combien‌ d’échantillons doivent‌ être moyennés et avec quel poids. Une table est également créée pour ‌chaque paire de fréquences. Ces⁣ méthodes ​surpassent largement ce que propose‍ PalmOS. Cependant,⁣ si le mixage était déjà⁣ complexe, cela ​l’est devenu encore plus. Décortiquons cela en étapes‌ plus simples. Tout‌ d’abord, nous avons⁤ besoin d’un format intermédiaire – un format avec lequel nous pouvons ‌travailler de manière efficace et rapide, ⁤sans perte de données significative. J’ai⁣ opté‌ pour un format à ‌virgule fixe ⁣de 32 bits avec 8⁣ bits pour la partie entière et 24 bits pour la partie fractionnaire. Étant donné qu’aucun appareil PalmOS n’a jamais produit d’audio à plus de‌ 24 bits de résolution, cela est acceptable. Le flux​ est conceptuellement simple : d’abord, on remplit un tampon​ intermédiaire de zéros. Ensuite, pour chaque flux⁤ dont‍ nous‍ avons‌ des tampons de données,⁢ nous‍ mélangeons ces tampons dans le tampon intermédiaire, avec rééchantillonnage si nécessaire. Ensuite, nous‌ coupons les échantillons du tampon intermédiaire, car⁢ le mélange de deux flux forts peut produire des valeurs dépassant le maximum autorisé. Enfin, nous convertissons⁢ le tampon intermédiaire dans le format pris en charge par le matériel et le⁣ transmettons à celui-ci.⁣ rePalm ne⁣ s’embarrasse pas⁣ d’un ‍tampon intermédiaire stéréo si le matériel audio est uniquement mono. Le tampon intermédiaire n’est en stéréo que‍ si le⁢ matériel le permet ⁣! Comment obtenons-nous cette flexibilité‍ ? Grâce à la manière dont nous mélangeons les éléments.

La seule partie difficile de ce processus est l’étape « mélanger les tampons⁤ dans‌ le tampon intermédiaire avec rééchantillonnage ». En ⁢effet, non seulement ‍nous devons rééchantillonner, mais nous devons également appliquer le volume, le ‍panoramique, et éventuellement convertir d’un format mono ‍à stéréo ou vice versa. L’approche la plus efficace⁤ consiste à écrire une fonction de mixage personnalisée ​et bien ajustée pour chaque⁤ combinaison possible d’entrées et de sorties. Le nombre de combinaisons est vertigineux. L’entrée a 8 taux possibles, 2 configurations de canaux possibles et 12 types d’échantillons possibles. La sortie a 8 taux possibles et 2 configurations de⁣ canaux. Cela signifie qu’il⁢ y‌ a un total de plus de 3‍ 000 combinaisons (8 * 2 * 12 * 8 * 2). Je ⁢n’allais pas⁤ écrire 3072 fonctions à la main. En ⁤fait, même les générer ⁢automatiquement‍ au moment de la construction (si j’avais ‌pu le faire) aurait gonflé la taille du ⁣code ⁤de rePalm à des mégaoctets. Non, une autre approche‍ était nécessaire.

J’ai décidé de réutiliser​ certaines connaissances acquises ⁤lors de l’écriture du JIT, ainsi que de réutiliser une partie de son ⁤code. En effet, lorsque vous créez un flux,‍ une fonction de mixage personnalisée est générée spécifiquement pour la configuration de ce flux et pour la configuration de ⁢sortie de votre matériel. Ce code d’assemblage personnalisé utilise tous les registres de ‍manière optimale et, en fait, il parvient⁤ à ne pas utiliser de pile du tout ! Le bénéfice est évident ! Le code de mixage est toujours optimal puisqu’il est personnalisé pour votre configuration. Par exemple, si le‍ matériel ne prend en ⁤charge que la sortie mono, le code de mixage effectuera un downmix avant l’upsampling‌ (pour⁤ traiter moins⁢ d’échantillons), mais ne fera un ‍downmix qu’après le downsampling ⁣(encore une fois, pour réduire‌ les calculs nécessaires). Étant donné qu’il existe trois cas principaux ⁢: upsampling, downsampling et pas de rééchantillonnage, il y‍ a trois chemins dans la génération de code pour produire des fonctions de mixage. Chaque fonction de⁣ mixage correspond à un prototype très⁤ simple :⁣ int32_t* (*MixInF)(int32_t* dst, const void** srcP, uint32_t maxOutSamples, void* resampleStateP, uint32_t volumeL, uint32_t volumeR, uint32_t numInSamples). Elle renvoie le pointeur⁤ vers le premier échantillon du tampon​ intermédiaire qui n’a​ PAS ‍été‌ écrit. srcP est mis à jour pour pointer vers le premier échantillon audio d’entrée ⁤non consommé, maxOutSamples limite le⁢ nombre⁢ d’échantillons audio pouvant être produits, numInSamples limite le ⁤nombre d’échantillons ​audio⁤ pouvant être ⁤consommés. ⁣Les fonctions de mixage retournent lorsque⁣ l’une ou l’autre limite est atteinte. La logique de ⁣rééchantillonnage peut avoir un état à long terme, ⁤donc cela est stocké dans une structure de ‍données par flux (5 mots) et passé ⁢en tant‌ que ⁣ resampleStateP. Le pointeur de la ⁣table de rééchantillonnage est encodé dans la fonction elle-même ​(pour des raisons de rapidité), car il ne changera jamais. ⁢Pourquoi⁤ ?‍ Parce que le taux d’échantillonnage du flux est constant, et le matériel ne pourra pas magiquement acquérir la capacité de ‌jouer à un autre taux d’échantillonnage plus tard. En revanche, le volume‍ et le panoramique du flux peuvent être modifiés à tout moment, donc ils ⁢ne sont pas codés en dur dans le corps de la fonction. Ils‍ sont fournis ⁤en tant⁢ que paramètres au moment du‌ mixage. J’ai même⁢ envisagé de les coder en dur ‌et de régénérer la fonction de mixage chaque fois que le volume ou ⁢le⁢ panoramique⁢ changeait, mais le gain aurait été trop ⁢faible pour⁢ être ⁤significatif, donc j’ai décidé ​de ne pas le faire. Au lieu​ de cela, nous pré-calculons simplement le « volume ⁢gauche » ⁢et le « volume droit » à partir des réglages ‍de l’utilisateur concernant le​ volume et le panoramique, et nous les passons⁢ à la fonction de mixage.

Avoir une fonction de mixage aussi efficace facilite le reste du mélangeur. Il suffit d’appeler la fonction de mixage ⁢pour chaque flux non mis en ⁣pause tant qu’il y a‍ des tampons à consommer et⁢ que le tampon de sortie n’est pas plein. Si nous consommons entièrement un tampon, nous le⁤ libérons‍ à l’utilisateur. Sinon, nous nous souvenons simplement du‍ nombre d’échantillons qui y⁤ restent pour plus tard. C’est tout ! Alors, toute cette machinerie complexe fonctionne-t-elle ? Oui, elle fonctionne ​! Le mélangeur audio ⁢compte environ 1 500 lignes de code, MAIS il peut rééchantillonner et mélanger ​des⁢ flux en temps réel à moins de 3 millions de cycles par flux par seconde, ce qui est bien ⁣meilleur que ce que ⁤faisait PalmOS, et avec une qualité supérieure !⁤ Le code se trouve dans « audio.c ».

Architecture du pilote ⁤audio de rePalm

La ⁤couche matérielle audio de rePalm est très simple. Pour un support audio‌ basique, il suffit de fournir les fonctions nécessaires et la couche sonore les appelle directement. Pour l’audio échantillonné, ⁤la fonction d’initialisation audio informe le ⁢mélangeur audio du nombre de canaux‌ natifs ‍et du taux d’échantillonnage. Qu’en est-il du format d’échantillon natif ? Le code fournit une fonction inline pour convertir un échantillon du format intermédiaire du ⁢mélangeur⁢ (entier signé 8.24) vers ⁣le format requis par le matériel.⁤ Ainsi, le format d’échantillon natif du⁢ matériel est‍ défini par cette fonction inline. Au moment de l’initialisation, la couche matérielle fournit au mélangeur toutes⁤ ces informations, ainsi‌ que la taille du tampon audio matériel. Ce tampon est nécessaire car les interruptions ont une ‍latence et nous avons besoin que⁣ le matériel audio ait toujours de l’audio ‌à jouer.

Sur⁢ la​ carte STM32F429, la sortie audio se fait sur⁤ la broche⁣ A5. L’audio⁤ est généré à l’aide d’un canal PWM, fonctionnant ⁤à 48 ‌000 échantillons par seconde, en mode mono. ⁤Étant donné que l’horloge PWM fonctionne à ‍192 ⁢MHz, si⁤ nous voulons‍ sortir 48 000 échantillons par seconde, l’unité PWM ne ⁣pourra compter que jusqu’à 4000. En ​effet, pour cette carte, qui ne dispose d’aucun matériel audio réel,⁤ nous sommes limités ‍à une précision d’environ 12 bits. Cela est suffisant pour des tests et ne sonne pas si‍ mal.​ La‍ sortie en mode single-ended ‌directement ⁢depuis ‍la broche‍ du​ microcontrôleur ne peut pas fournir beaucoup de⁣ puissance, mais ⁣avec un petit haut-parleur, le son est clair et agréable ! Je publierai⁤ bientôt⁢ une ​image avec le‍ support audio.

Sur reSpring, l’horloge du CPU (et donc l’horloge PWM) est à 196,6 MHz. Pourquoi cette ‌fréquence étrange ?‍ Parce qu’elle est précisément 48 000 x 4096. Cela nous permet d’éviter de devoir mettre à l’échelle l’audio de manière complexe, comme nous le faisons sur ​la carte STM32F429.⁢ Il suffit de⁣ le saturer à 12 bits. De plus, sur reSpring, deux broches sont utilisées pour la sortie audio, en polarité opposée, ce qui nous​ donne le double de l’amplitude de tension, produisant des‍ sons plus forts.

Microphone

Je n’ai pas implémenté de mélangeur/rééchantillonneur pour le microphone – PalmOS n’a jamais pris en‌ charge plus d’un utilisateur ⁤d’un microphone à la fois, donc pourquoi s’en soucier ? – aucune application ne le fera. ​Au lieu de cela, quel que soit le taux d’échantillonnage demandé,⁣ je‌ le ‍transmets au pilote matériel et le fais fonctionner à ce taux ⁤d’échantillonnage. En ce qui concerne le type d’échantillon, c’est le même que pour la sortie audio, une fonction personnalisée est générée pour convertir​ le format d’échantillon de l’entrée (mono 16 bits little-endian) vers le format requis. Le code‌ généré est ‌assez​ compact et fonctionne bien !

Support Zodiac

Introduction au Tapwave Zodiac

Le Tapwave Zodiac, lancé en 2003, était un appareil PalmOS atypique, principalement conçu pour ​le jeu vidéo. Il se distinguait par un écran en mode paysage,‌ un joystick analogique, une⁤ puce Yamaha Midi,⁤ ainsi​ qu’un accélérateur graphique ATI Imageon⁣ W4200 doté de sa ‌propre mémoire ​graphique. Plusieurs titres⁤ exclusifs à Tapwave⁢ ont été développés, exploitant efficacement ce nouveau ​matériel, y ⁢compris⁣ des jeux 3D impressionnants. Bien ⁢entendu, ce matériel innovant ⁤nécessitait un ​support au niveau du système⁤ d’exploitation. Tapwave a introduit plusieurs nouvelles API, qui ont été bien⁢ documentées, facilitant ainsi leur utilisation. La conception ‌de cette nouvelle API était soignée et intuitive. La documentation ⁣était presque parfaite. Bravo à Tapwave ! J’avais ​bien sûr l’intention de prendre en charge les jeux Tapwave dans rePalm.

Ingénierie inverse

Les API personnalisées de Tapwave étaient accessibles via une ⁢vaste table de pointeurs de fonction, fournie à toutes les applications ciblant Tapwave, après⁢ vérification de leur signature (Tapwave exigeait des ⁢approbations et une‌ signature des applications). Cependant, il⁢ était évident qu’elles devaient interagir avec‍ une bibliothèque ou du ‌matériel. En explorant, j’ai découvert que⁢ la plupart d’entre elles faisaient⁢ appel à la Tapwave Application​ Layer (TAL). Ce module est particulier, car sur le Zodiac, à l’instar de DAL, Boot et⁤ UI, le TAL peut ​être accédé directement via R9 avec l’instruction LDR R12, [R9, #-16]; LDR PC,⁣ [R12, #4 * tal_func_no]. Après avoir passé beaucoup⁣ de temps‌ dans le TAL, j’ai réalisé qu’il ne s’agissait que d’un wrapper. Les autres bibliothèques, comme la Tapwave Midi Library et⁣ la Tapwave Multiplayer Library, étaient également des wrappers. La véritable richesse fonctionnelle se⁣ trouvait dans le DAL, qui offrait un nombre impressionnant de points d’entrée. Alors que les DALs PalmOS classiques en ‌comptent environ 230, celui ⁣de Tapwave en possède 373 !

Après de nombreuses heures ⁤de traçage‌ dans le TAL et d’exploration ‌des documents techniques du processeur, j’ai pu ​identifier les noms et paramètres de ​la plupart ‍des fonctions exportées supplémentaires du DAL. J’ai réussi à‌ déduire le‌ fonctionnement de presque ​toutes, sauf 14 fonctions dont je n’ai trouvé aucune utilisation dans le logiciel de l’appareil. Les ⁢implémentations réelles sont moins importantes puisque je les réimplémente. Mes principales préoccupations concernaient, bien‌ sûr, les API d’accélération graphique. ‌Étonnamment, cette partie s’est révélée être la plus simple à mettre en œuvre !

L’accélérateur graphique

L’accélérateur graphique du Zodiac était assez avancé pour un appareil portable de l’époque, bien qu’il soit relativement basique. Il‌ disposait de 8 Mo de mémoire⁢ intégrée et ne gérait que les opérations 2D. il pouvait : copier des ‌rectangles de ‌données d’image, mélanger ⁤des rectangles entre couches avec‍ un​ alpha blending‌ constant ou paramétrique, effectuer un redimensionnement bilinéaire basique, et dessiner des lignes, des‍ rectangles et ⁣des points. Son fonctionnement se limitait aux couches RGB565LE en 16 bits. La mise en œuvre de ces fonctionnalités s’est avérée relativement ​simple. Bien que le traitement logiciel ne soit pas rapide,⁤ cela suffisait pour mon prototype. Après quelques jours de travail,⁣ cela fonctionnait ! Plusieurs​ jeux ont pu être lancés.

La prochaine étape, toujours en cours, consiste à utiliser l’unité ​DMA2D du STM32 pour accélérer la plupart des opérations que ⁣l’accélérateur ATI pouvait​ réaliser. À l’exception du redimensionnement d’image, cela peut être ⁣effectué en un ou deux passages ! Pour couronner le tout, il peut également ⁣fonctionner ‍en‌ arrière-plan, comme le faisait la puce ATI pour le CPU du Zodiac. ‌Mais cela, c’est pour plus tard…

Autres API de Tapwave

Le ⁣sous-système d’entrée du Zodiac était assez ‌particulier et nécessitait un certain ‌travail. Au lieu des méthodes habituelles de PalmOS pour lire les touches, le⁢ tactile, etc., ⁣ils ont introduit un nouveau mécanisme de « file d’attente d’entrée » qui permettait de centraliser tous ces ‍événements. J’ai⁤ dû réimplémenter⁤ cela à partir de rien, en me basant uniquement sur‍ l’API de haut niveau ⁣documentée⁣ et​ la désassemblage. Cela‍ a fonctionné : rePalm dispose désormais d’une implémentation fonctionnelle de TwInput, qui peut servir de référence à quiconque souhaitant également l’implémenter.

TwMidi a été principalement reverse-engineered en une semaine. Cependant, je n’ai pas⁤ encore ⁢développé de ​séquenceur MIDI. Je​ pourrais le faire et je le ferai, mais pas tout de suite. L’API est connue et c’est tout ce dont j’avais besoin pour renvoyer des codes d’erreur appropriés, permettant ⁤ainsi au reste du système de continuer à fonctionner.

Technologie matérielle réelle : reSpring

L’accessoire ⁣ultime pour Springboard

Lorsque ⁤Handspring a lancé le Visor, son emplacement d’extension Springboard était l’une des⁢ fonctionnalités les plus révolutionnaires. Il permettait d’ajouter divers dispositifs d’extension, tels⁢ que des téléphones cellulaires, des récepteurs GPS, des lecteurs de codes-barres, des lecteurs de cartes‌ d’extension et des caméras.⁣ L’emplacement⁤ Springboard est intéressant car il constitue ⁣une connexion directe au bus ⁤de données et⁢ d’adresses du ⁣CPU, offrant⁢ ainsi⁢ de nombreuses possibilités d’expansion. J’ai décidé ‌que la ⁤première application de ⁢rePalm serait un​ accessoire Springboard qui, une fois branché, mettrait à niveau un Visor vers‌ PalmOS 5. L’idée est que ‌reSpring exécutera ⁣rePalm sur son propre CPU, tandis que le Visor servira d’écran, de ⁤tactile et de boutons. ⁤J’ai collaboré avec George Rudolf Mezzomo sur reSpring, ‌moi définissant les spécifications, lui réalisant les schémas et la mise​ en page, ⁣et moi développant ⁣le logiciel et les pilotes.

Interface avec le Visor

Pour le Visor, le module Springboard‍ apparaît comme⁢ deux zones de mémoire (deux lignes de sélection ‌de puce), chacune ayant une taille maximale ⁣de quelques mégaoctets. La première doit contenir une ‌image ROM valide que le ‍Visor peut détecter, structurée comme ‌une mémoire ROM PalmOS, avec un seul‌ tas. En général, ce tas contient une seule application ⁣- le⁣ pilote de ce module. Pour reSpring, j’ai​ décidé d’adopter une approche différente. Plusieurs raisons motivent ce choix. La principale était​ qu’une mémoire flash ‍NOR pour stocker la ROM occuperait ⁣de l’espace sur la carte, ‌mais​ je ne⁢ voulais ⁤pas non⁤ plus gérer de nombreux composants flashables différents sur​ la carte. Il y avait une troisième raison, mais ​nous y reviendrons plus tard.

Le Visor s’attend à⁣ interagir avec le Springboard en effectuant des accès mémoire (lectures et‍ écritures), et le module doit se ​comporter comme ​un dispositif mémoire synchrone. Cela signifie qu’il n’y a pas de ligne « je suis prêt à répondre », mais plutôt‌ un nombre fixe de cycles ‍pour⁢ répondre à ⁣toute demande. Lorsqu’un module est inséré, le Visor configure ce nombre à six, mais ​il peut ensuite être réduit par l’application pilote⁣ du‍ module. Essayer de répondre à des demandes avec un délai fixe‌ (et très court) serait une charge CPU énorme⁢ pour notre processeur ​ARM. J’ai donc décidé que la⁤ solution la plus simple serait d’intégrer une RAM, permettant ainsi au Visor d’y accéder. Mais comment y accéder si le‍ Visor peut le faire à tout moment ? Eh bien, il existe des types spéciaux de RAM qui permettent ⁣cela.

Oui, la fameuse (et coûteuse) RAM à double port. ⁢J’ai décidé que reSpring utiliserait une petite quantité de RAM à double port comme boîte aux lettres​ entre le Visor et le CPU⁢ de ⁤rePalm.⁢ De cette manière, le Visor pouvait⁣ y accéder à tout⁢ moment, tout comme rePalm. ⁣L’emplacement Springboard dispose‌ également de deux lignes ‍de demande ‌d’interruption, une pour​ le Visor et une pour le module. Celles-ci peuvent être​ utilisées pour signaler lorsqu’un message est dans la‍ boîte aux lettres. Cependant, deux problèmes se posent. Le premier est que les RAM à double port sont généralement volumineuses, principalement en raison du grand nombre de broches nécessaires. Étant donné que le Visor nécessite une mémoire ⁣de 16 bits⁢ dans l’emplacement Springboard, ⁢notre⁣ RAM à double port hypothétique devrait ‍également être de 16 bits. Ensuite, nous avons besoin​ de lignes d’adresse, de lignes de contrôle, ⁣de⁢ lignes ⁣de sélection de byte, et de lignes de sélection de puce. Si nous devions utiliser une mémoire‌ de 4 Ko, par exemple, nous aurions besoin de‌ 11 lignes d’adresse, 16 lignes de ‌données, 2⁢ lignes ‍de sélection ‍de byte, une ligne de sélection de puce, une ligne d’activation de sortie, et une ligne d’activation d’écriture, PAR PORT ! Ajoutez au⁣ moins deux broches d’alimentation, et notre ‌puce hypothétique devient un monstre de 66 broches. ​Étant donné que les packages de‌ 66 broches n’existent pas, nous serions ‍contraints d’utiliser une⁢ pièce de 100 broches. ⁢Et 4⁣ Ko, ce n’est même pas beaucoup. Idéalement, nous aimerions y intégrer notre framebuffer entier ​pour⁤ éviter des ‍transferts complexes. Malheureusement, comme l’a dit le grand philosophe Jagger, « On ne peut ⁣pas toujours avoir ce que l’on veut. » Les RAM à ​double ⁢port⁢ sont‍ très coûteuses. Il n’y‌ a que deux entreprises qui les‌ fabriquent, et elles demandent beaucoup. J’ai⁣ donc opté​ pour 4

KB part uniquement basé sur le coût. ⁣Même à cette‌ taille modeste de 4 Ko, cette RAM est de​ loin le composant le plus coûteux de la carte, à 25 $. Étant donné que ‌les coûts⁢ d’intégration d’une pièce de 64 Ko (ma taille préférée) dépassaient​ mes attentes (et les ​capacités ‌de mon portefeuille), j’ai décidé d’inventer un ​protocole de messagerie complexe et de le faire fonctionner avec une RAM de 4 Ko utilisée comme une boîte aux lettres bidirectionnelle.

Revenons à notre besoin d’une ROM pour‌ contenir notre⁤ programme de pilote. Nulle part dans les⁤ spécifications de Sprinboard il n’y a réellement une exigence pour une ROM, juste une mémoire. ‍Que signifie cela ? Nous pouvons ⁣éviter ​ce chip supplémentaire en intégrant l’image ROM dans le CPU reSpring, et en l’écrivant rapidement dans⁣ la RAM à double port‌ au démarrage. Éliminer une puce à acheter et à placer sur la carte est fantastique !

Version 1

Je l’admets : il y a eu un peu de dérive fonctionnelle, mais⁢ le design final​ du matériel pour la version 1 s’est avéré être : 8 Mo ⁤de RAM, 128 Mo⁣ de flash NAND, un‍ CPU à 192 MHz avec 2 Mo de flash pour ​le système d’exploitation, un emplacement pour carte microSD, un haut-parleur pour la⁢ sortie audio, et un amplificateur⁢ pour utiliser​ le microphone intégré du Visor pour⁢ l’entrée audio. La⁢ sortie audio sera‍ réalisée de la même manière que sur la carte STM32F429, tandis que l’entrée audio se fera ​via le véritable ADC. La RAM principale fonctionne sur un⁤ bus de 32 bits à 96 MHz (bande passante de 384 Mo/s). Le flash NAND est sur‍ un bus QSPI à 96 MHz (bande passante de 48 Mo/s). Le système d’exploitation sera stocké dans la mémoire⁢ flash interne du​ CPU STM32F469.⁣ Le⁤ NAND embarqué est juste⁢ une ‌exploration que j’aimerais réaliser.⁣ Ce‌ sera soit une carte SD ⁤interne, soit un stockage pour quelque chose comme NVFS (mais​ pas aussi instable), lorsque j’aurai ⁣le temps de l’écrire.

Alors, quand cela se produira-t-il ? Cinq cartes de version 1 m’ont ‍été livrées fin⁣ novembre 2019 !

Mise en route de la version 1

Avoir le matériel en main est formidable. C’est ‌encore mieux quand​ tout fonctionne correctement dès le premier essai. Fantastique comme des licornes, et tout‍ aussi probable. Non… ⁣rien⁣ n’a fonctionné tout de suite. Les cartes ne voulaient⁣ pas communiquer avec le débogueur du tout, ‌et après des semaines de torture, j’ai réalisé qu’il manquait des résistances de tirage sur​ les cartes. Ce n’était ​pas un problème sur les‍ cartes de développement⁤ de STM, car elles incluent ces résistances. Une fois que le​ CPU a commencé à​ communiquer avec moi, il est devenu ⁢évident ⁢très rapidement qu’il était très ​instable. Il est spécifié pour fonctionner à 180 MHz (oui, cela signifie que⁤ normalement nous l’overclockons⁣ de 9,2 ⁣% à 196,6 MHz). Sur ‌les cartes ⁢reSpring, le CPU ne fonctionnait pas avec une stabilité supérieure à 140 MHz. J’ai vérifié l’alimentation et les condensateurs de découplage. Tout semblait en place, jusqu’à ce ⁣que… VCAP1​ et VCAP2 soient absents. Le‍ cœur du CPU fonctionne à une tension‌ inférieure à 3,3‍ V, donc le CPU a un régulateur interne.​ Ce régulateur a besoin de condensateurs pour stabiliser sa ⁢sortie face à une consommation variable par ⁢le CPU.​ C’est à cela que servent les ⁣broches⁣ VCAP1 et VCAP2. Eh bien, la carte n’avait⁣ pas de condensateurs sur VCAP1 et⁣ VCAP2. La sortie du régulateur interne oscillait énormément ⁢(+/- 600 mV sur une ⁤alimentation de 1,8 V, c’est beaucoup de fluctuation !). ⁤En fait, il est incroyable ⁣que ‍le CPU ait fonctionné avec une alimentation aussi instable !⁣ Après une⁢ autre ‌reconfiguration sous le microscope avec⁤ l’ajout de ⁤deux condensateurs, la carte était stable. Passons au problème suivant…

Le problème suivant concernait la ‌SDRAM. C’est l’endroit principal⁣ où le code s’exécute et où les données ‌sont stockées. L’interface semblait complètement défaillante. ‍Chaque mot écrit, le 15ème bit se lisait toujours comme 1, ​et les 0ème et 1er bits se lisaient toujours comme zéro. Inutile de dire que cela n’est pas acceptable ⁣pour⁤ une RAM dont j’espérais exécuter ​le code.‍ Cela a été un véritable casse-tête à déboguer, mais il ​s’est avéré qu’il y avait une⁣ faute de ⁢frappe dans la configuration⁣ GPIO qui‌ ne mappait pas⁤ les deux bits inférieurs à SDRAM DQ0 et DQ1.⁢ Cela laissait seulement le bit 15 bloqué ⁤à l’état haut à⁣ résoudre. ​Ce problème ne s’est pas reproduit sur d’autres cartes, donc c’était⁣ un problème local à une seule carte. Un examen minutieux au microscope a révélé une boule de soudure sous la broche laissée par le PCBA, qui court-circuitait une broche voisine qui était haute. Soulever la broche, enlever la soudure et reconnecter la broche au PCB a‍ résolu ce problème.‌ La SDRAM fonctionnait maintenant. Étant donné que cette SDRAM était assez différente ‌de ​celle de la carte de découverte STM32F429, j’ai dû rechercher les configurations à utiliser pour elle, et traduire entre les temps utilisés par STM ‌et ceux du datasheet de la RAM pour obtenir les réglages ⁢appropriés. Le ​résultat était une ​SDRAM assez rapide qui semble stable. Génial !

Bien sûr, ce n’était pas du tout la fin. Je ne pouvais pas accéder‌ à la ⁤SRAM à double port. Une vérification rapide du schéma de la carte a révélé que sa broche de sélection de puce n’était‍ pas du tout connectée au STM. J’ai sorti le‌ microscope​ et le fer à souder, et j’ai‌ ajouté un fil. Et voilà, la ⁤SRAM était ⁤accessible.‌ Plus de lecture de ‍datasheet a suivi pour‌ la configurer correctement. En faisant cela, j’ai remarqué que sa consommation d’énergie est indiquée comme « faible », seulement 380⁤ mW ! Donc, non seulement c’est la puce la plus ⁤coûteuse de la ⁤carte, mais c’est ‌aussi ‍la​ plus énergivore !⁤ Il ⁣faut vraiment que cela change⁣ !

Je pourrais ⁣vous parler de nombreuses autres reconfigurations qui ont suivi après quelques tests dans le Visor, juste⁣ pour garder​ toute l’histoire de reconfiguration​ ensemble. Il s’est avéré que la ligne pour interrompre le Visor n’était jamais connectée nulle ⁣part, donc je l’ai câblée à PA4, afin que reSpring puisse envoyer une IRQ au ⁤Visor. Il s’est également avéré que la SRAM a beaucoup de « modes » et qu’elle était configurée pour le mauvais. Trois ⁢broches ‍distinctes ont​ dû être reconfigurées pour passer du mode « maître » au mode « esclave ». Ces modes configurent comment plusieurs SRAM peuvent être utilisés ensemble. Comme reSpring n’en a qu’une, logiquement, elle‍ était configurée comme maître. Cela s’est avéré être une erreur. Oups.

Intégration dans un Visor ?

Reconnaissance

Alors ​simple, n’est-ce pas ? Il suffit de l’insérer dans le​ Visor et de terminer ⁢? ​Lire et ⁤relire le Guide de développement Springboard de Handspring fournissait⁤ presque toutes les informations nécessaires, en théorie. ‍La‌ pratique était différente. ⁢Pour une raison quelconque, peu importe comment je formattais la fausse ROM dans la SRAM partagée, le Visor ne la reconnaissait pas. j’ai abandonné cette ‌approche et écrit une application de test pour simplement afficher ce que⁣ le Visor voit à ⁣l’écran, dans une série​ de boîtes de ⁣message. La ‌ROM Springboard est toujours mappée à 0x28000000. J’ai rapidement réalisé les problèmes. Tout d’abord, le‌ Visor‌ effectue un ⁤échange de bytes sur tous⁣ les accès. Cela est dû au fait que la plupart du monde est ⁣en little-endian,⁣ tandis que le CPU 68k est en big-endian. Pour permettre aux concepteurs⁤ de périphériques de ne pas s’inquiéter, Handspring échange les​ bytes sur le bus. « Mais, » pourriez-vous dire, « qu’en est-il⁢ des accès non-mots ? » Il⁢ n’y a pas de tels accès. Le Visor accède toujours à 16 bits à la fois. Il n’y a ​pas de lignes de sélection de bytes. ⁢Pour nous, c’est ⁣en fait plutôt cool. Tant que nous communiquons en ⁢utilisant uniquement des quantités de 16 bits, aucun échange ‌de bytes dans ⁣le logiciel n’est nécessaire. Il y avait un autre problème : le Visor voyait chaque autre mot que reSpring écrivait. Cela​ a nécessité quelques investigations, mais le résultat était​ à la fois hilarant et triste ​en même ​temps. Malgré tous les accès à Springboard‍ étant ⁣de 16 bits de large, la ligne d’adresse 0 est câblée au connecteur Springboard. Pourquoi ? Qui⁢ sait ? Mais ​elle est toujours basse. ‌Sur la carte reSpring, le connecteur Springboard A0 ⁤était câblé à‍ RAM A0. Mais comme il est toujours à 0, cela signifie que le Visor ne peut accéder qu’à chaque autre mot de RAM – les adresses paires.⁢ …soupir…⁣ Donc, nous n’avons⁢ pas⁣ 4 Ko de RAM partagée. Nous avons 2 Ko… Mais maintenant que nous savons tout ⁣cela, pouvons-nous faire reconnaître reSpring comme un module‌ Springboard⁤ ? OUI !⁤ L’image à droite‌ a été prise la première fois que le module reSpring a été reconnu⁢ par le Visor.

Économie d’espace précieux

Bien sûr,⁤ cela a été…

Défis Initiaux

Les⁣ difficultés ne font que​ commencer. Les applications‍ s’exécutent ⁢directement à partir de la mémoire ROM du module, ce ⁣qui présente des avantages et des inconvénients.‌ Pour nous, cela s’avère principalement problématique.⁣ Que cela signifie-t-il ? L’image ROM que nous plaçons dans la SRAM‍ doit y rester indéfiniment. Par ‍conséquent, il ​est crucial de la rendre aussi petite ⁣que⁣ possible. J’ai consacré beaucoup d’efforts à réduire sa taille, atteignant environ 684 octets.‍ La plupart de⁤ mes‍ tentatives pour⁣ superposer des structures afin ​d’économiser de l’espace n’ont pas ⁣abouti, car le code⁣ Visor qui valide la ROM​ sur le module Springboard ⁢est impitoyable. L’application elle-même est minuscule. Elle met en œuvre le protocole de messagerie le plus simple possible (un mot à la fois) ⁤pour ⁢communiquer avec le STM. Elle ne prend pas en charge les graphiques ni le stylet. Alors, que fait-elle réellement ? Elle télécharge un morceau de code plus volumineux, mot par mot, depuis le STM. Ce code est stocké dans la RAM du Visor⁢ et peut y être exécuté. Ensuite, il suffit de sauter à ce code. Pourquoi ? Cela nous permet d’économiser de l’espace précieux dans la SRAM. Au final, nous disposons de 2 Ko – 684 octets = 1,3 Ko de RAM pour l’échange de données. Ce n’est pas‌ beaucoup, mais cela pourrait suffire.

Protocoles de Communication

Avec 1,3 Ko de RAM partagée⁣ et une ​interruption dans chaque direction, comment communiquons-nous ? J’ai conçu deux protocoles de communication :⁤ un⁣ simple et un ‍complexe. ​Le protocole simple est utilisé uniquement pour charger le code plus volumineux dans la RAM du Visor. Il envoie un message de ‍16 bits et reçoit une réponse de 16 bits. ⁣Les messages sont assez basiques : une⁤ demande ​de réponse pour vérifier‍ la‍ communication, quelques requêtes pour obtenir des informations⁤ sur les emplacements des grandes⁤ boîtes‍ aux lettres pour le‌ protocole ​complexe,⁣ une demande pour connaître la taille du code téléchargé, et​ le message pour télécharger le mot suivant du ⁣code. Une fois ‍le code téléchargé⁣ et conscient des emplacements et‌ tailles des boîtes aux ⁣lettres, il utilise le protocole complexe. En quoi cela diffère-t-il‌ ? Un gros morceau de données est placé dans la boîte aux lettres, puis le protocole‌ simple est utilisé pour indiquer une demande et obtenir une réponse. Les boîtes ‍aux lettres ⁣sont​ unidirectionnelles et de⁣ tailles très⁣ différentes. La boîte aux lettres du STM vers le Visor occupe environ 85 ‍% de l’espace, tandis que celle dans l’autre direction est minuscule. La raison est ‌évidente : les données d’écran sont volumineuses.

Toutes les demandes proviennent toujours ‌du Visor et reçoivent ⁣une réponse du module reSpring. Si le module a quelque chose à communiquer au ⁣Visor, il déclenche une IRQ, et le ⁣Visor envoie une demande pour ⁢les données. Si ⁢le Visor n’a rien à envoyer, il envoie ⁣simplement un message NOP vide. Comment le Visor envoie-t-il une demande ? D’abord, les⁢ données sont écrites dans la⁢ boîte aux lettres, puis le type ⁢de message est écrit à un emplacement spécial de la SRAM, et enfin, un marqueur spécial indiquant que‌ le message est ⁢terminé est ⁢écrit à un autre emplacement de la SRAM. Une IRQ ‌est ensuite ‌déclenchée vers le module. Le gestionnaire ⁢d’IRQ dans le STM ⁢recherche ce marqueur « message valide », et s’il est trouvé, le message est lu et une‍ réponse est donnée : d’abord, les données sont écrites dans la boîte aux ⁣lettres, puis le type⁢ de message est écrit à l’emplacement⁤ SRAM partagé pour le type ⁤de ⁤message, et enfin, le marqueur « c’est une réponse » est écrit à l’emplacement de marqueur SRAM. Pendant ce temps, le Visor lit en boucle l’emplacement de marqueur SRAM en attendant qu’il change. Cette attente active pose-t-elle ⁤un problème ? Non. Le STM est si rapide, et ⁤le code ⁣pour gérer l’IRQ effectue si peu de traitement que​ les réponses arrivent souvent en quelques microsecondes.

Support Précoce ‍du Visor

À ce stade, certaines fonctionnalités⁣ de⁤ base⁢ pouvaient être testées, mais elles échouaient toutes sur le⁤ Visor ⁤Deluxe et ‍le Visor Solo. En fait, tout plantait peu⁣ après l’insertion du module.​ Pourquoi ? La raison est ⁣en réalité évidente : ils fonctionnent​ sous⁤ PalmOS 3.1, ⁢tandis que tous les‌ autres Visors ⁢fonctionnent sous PalmOS⁤ 3.5. Un​ nombre surprenant d’API sur lesquelles on compte dans la programmation‍ PalmOS ne sont tout⁣ simplement pas disponibles ⁢sur PalmOS 3.1. Des fonctions simples comme ErrAlertCustom(), BmpGetBits(),⁢ WinPalette(), et WinGetBitmap() n’existent tout simplement pas. J’ai dû écrire du code pour éviter de ‌les utiliser ⁢dans PalmOS ⁣3.1. Mais certaines d’entre elles sont nécessaires. Par exemple, comment copier ⁤directement des bits‌ dans le ⁤framebuffer d’affichage si ‌je ne peux pas obtenir ‍un pointeur vers le framebuffer via BmpGetBits( WinGetBitmap( WinGetDisplayWindow ())) ? J’ai tenté de plonger dans les structures des fenêtres et des bitmaps moi-même, mais il s’avère que le ‌bitmap d’affichage ⁣n’est pas un bitmap valide dans‍ PalmOS 3.1. ⁤j’ai réalisé que PalmOS 3.1 ne supportait ⁤que les ‍processeurs ​MC68EZ328 et MC68328, et que les ‌deux configurent l’adresse de base du contrôleur d’affichage ⁣dans ⁤le même registre,⁢ donc je​ l’ai simplement lu directement. Quant à la configuration de la palette, elle n’est pas nécessaire puisque PalmOS 3.1 ne prend pas en charge les couleurs ou les palettes. C’est assez simple.

Optimisation des​ Performances

Données Initiales

Certaines données sont nécessaires pour que rePalm puisse démarrer ⁢correctement : la résolution de l’écran et les profondeurs supportées, les indicateurs matériels (par​ exemple : si‍ l’écran a un réglage de ‌luminosité ou de contraste), et⁣ si⁣ l’appareil dispose d’une LED d’alerte (oui, vous avez bien lu, plus d’informations ‍à ce sujet plus ‌tard). Ainsi, rePalm ne ⁣démarre pas tant qu’il n’a pas reçu un message⁤ « continuer⁤ le démarrage » envoyé par le code sur le Visor une fois ⁤toutes ces informations collectées.

Transmission des Données d’Affichage

Les ‍données à​ plus haut débit que ⁤nous devons transférer⁢ entre le Visor et le module reSpring sont les données d’affichage. Par ⁣exemple, pour ⁢un écran de 160×160 pixels à 16 bits par pixel à 60 images par seconde, nous devrions transférer 160x160x16x60=23,44 Mbps. Ce n’est‌ pas un faible ⁣débit‍ à tenter sur un CPU 68k ⁣à 33 MHz. En fait, je ne pense pas⁤ que cela ⁤soit même possible. Pour un niveau de gris à 4 bits par pixel,‌ les⁤ chiffres⁤ semblent‍ un ⁣peu meilleurs : 160x160x4x60=5,86 Mbps. Mais il‍ y a un ⁣second problème.‌ Chaque message nécessite un aller-retour​ complet. Nous sommes limités par ⁤la latence ‍d’interruption du Visor et notre latence générale ⁢d’aller-retour. Malheureusement, cette⁣ latence peut ‌atteindre 2 à 4 ms. Nous devons donc⁣ minimiser le nombre de paquets‍ envoyés. Nous y reviendrons plus tard. Au départ, j’envoyais les données morceau⁣ par⁢ morceau ​et les‌ affichais à l’écran. Cela a-t-il fonctionné ‍du premier coup ? En fait, ‌presque. L’image à droite ⁢montre les résultats. Il a suffi d’un simple⁤ échange ⁤de⁢ bytes pour ​que cela fonctionne parfaitement !

Cependant, c’était assez lent, environ 2 images par seconde. En y regardant de plus près, j’ai réalisé que l’appel à MemMove était l’une des raisons. J’ai écrit une routine optimisée pour déplacer de gros blocs de données, étant donné qu’ils n’étaient pas superposés et​ toujours alignés. Cela a amélioré le taux de rafraîchissement à environ 8 images par seconde sur les appareils en niveaux de gris. ⁣D’autres améliorations ‍étaient⁢ nécessaires. Le principal problème était le temps d’aller-retour pour copier les données, attendre, les copier à nouveau, et ainsi de suite. ⁢Comment minimiser ⁢le nombre d’aller-retours ​? Oui, en compressant les données. J’ai⁣ écrit un compresseur⁤ d’images sans‍ perte très rapide sur le STM. Il fonctionne⁣ un peu comme LZ, avec une table de hachage​ pour trouver les occurrences précédentes d’un motif de données. Les taux de compression étaient très bons,⁤ et les taux ⁣de rafraîchissement ont atteint ​30 à 40 images par seconde sur les appareils en niveaux de gris. Le Bejeweled en couleur est ‍devenu jouable même⁣ !

Obtenir les données d’affichage était également assez ⁢intéressant. PalmOS 5 s’attend à⁣ ce que ‍l’affichage soit simplement un framebuffer qui peut être écrit librement. Bien qu’il existe des‍ API pour dessiner, on peut ⁢également écrire⁣ directement dans le ‍framebuffer. Cela signifie qu’il n’y a pas vraiment de moyen d’être ⁢notifié lorsque l’image à l’écran change. Nous pourrions ⁣envoyer les données d’écran en continu. En fait, c’est ce que j’ai fait au départ. Cela ​épuise ⁤la‌ batterie du Visor d’environ deux pour cent par minute.

Optimisation de l’Utilisation de la Mémoire⁤ et de l’Énergie

Lorsqu’un processeur est​ constamment sollicité, il peut ⁣entraîner une consommation excessive⁣ de ressources. Pour éviter cela,‍ il ‍est essentiel de trouver un moyen efficace de recevoir des notifications lors de l’exécution de⁢ certaines tâches. Une solution innovante‍ consiste à utiliser l’Unité de Gestion⁤ de la Mémoire (MPU). En protégeant le tampon d’affichage⁣ contre les ⁢écritures,⁢ nous permettons ⁣uniquement⁤ les lectures. En ⁤cas d’écriture, une exception est ⁣déclenchée. Nous⁤ gérons cette exception en programmant ​un minuteur⁣ pour ‌1/60 de seconde, après quoi⁣ nous autorisons les écritures et reprenons le processus. Le⁤ code qui était en cours d’exécution continue sans interruption. Lorsque le minuteur se déclenche, ‌nous‌ verrouillons à nouveau le tampon d’affichage et demandons le‍ transfert ​d’une image ⁢complète à Visor. ⁢Cela nous permet d’éviter d’envoyer les mêmes données à plusieurs ⁤reprises. De plus,⁣ certaines ‍écritures à⁣ l’écran peuvent⁤ ne rien changer,‌ ce qui m’a conduit à ajouter une couche supplémentaire : chaque fois ‍que ⁢nous envoyons une image, nous ‍en conservons ‍une copie. Lors​ de la ⁣prochaine demande, nous comparons ⁤les images et n’effectuons aucune action si elles sont identiques. Grâce à la‌ compression et à ces deux ⁣techniques, nous parvenons à une utilisation raisonnable de l’énergie et à un taux​ de rafraîchissement d’écran⁢ satisfaisant.

Gestion des Boutons, Stylet, Luminosité et Informations ⁢sur la⁣ Batterie

Le Visor a la ⁢capacité d’envoyer des données au module reSpring⁤ à tout moment, ce qui facilite l’envoi d’informations sur ⁤les boutons et le stylet. Pour le transfert de données dans l’autre sens, le design est tout aussi ⁤simple.​ Si le module demande une interruption​ (IRQ), le Visor envoie ‌un message NOP, et en réponse, le module transmet‍ sa ‍demande. Les requêtes peuvent concerner la‌ palette d’affichage, la luminosité, le contraste ⁢ou les informations sur⁣ la batterie. Le Visor exécute ⁢l’action demandée et peut⁣ éventuellement répondre,⁣ par exemple, pour les informations sur la batterie.

Support du Microphone

Sur les premières versions des cartes, l’amplificateur audio était mal⁣ câblé, mais‍ après quelques⁢ modifications complexes, il a été possible de tester la fonctionnalité d’enregistrement audio de base. Cela a fonctionné ! Bien que la qualité ne soit pas optimale, j’ai pu reconnaître ma⁤ voix en disant « 1 2 3 4 5 6 7 » à l’application de mémos vocaux. Cependant, amplifier le microphone du Visor s’est avéré compliqué, nécessitant un gain de 40 dB⁢ pour obtenir des​ résultats ‌exploitables. Les composants analogiques nécessaires pour réaliser​ cela de manière⁤ efficace et sans bruit sont trop coûteux⁣ et ​nombreux.⁤ Ainsi, pour la version 2, il a été décidé d’intégrer un microphone numérique sur la carte, ce qui‍ s’est avéré⁤ moins cher. De plus, éviter l’analogique est souvent la meilleure option pour une carte !

Améliorations Techniques

Transmission Série/IrDA

J’ai intégré la possibilité de transférer le port série du Visor vers reSpring. À quoi cela sert-il ? Principalement ⁣pour‌ le HotSync ‌(qui fonctionne) et le transfert IR (qui fonctionne en grande partie). Cela représente un défi ⁢technique.​ Pour prendre⁣ en charge PalmOS 3.1, ​il est nécessaire d’utiliser l’API​ de l’Ancien Gestionnaire Série. N’ayant jamais utilisé cette API, j’ai dû m’adapter. Les API sont similaires, mais peu conviviales pour nos besoins. Nous​ devons être ‌informés de ⁤l’arrivée de données sans avoir à les vérifier constamment, ce‍ qui consomme de la batterie. J’ai finalement découvert ⁣qu’en utilisant la « fenêtre de réception » et le « gestionnaire de réveil », je pouvais obtenir un ⁢rappel lorsque des données arrivaient. J’ai également trouvé un moyen ⁤d’augmenter la taille du tampon de réception, ce qui permet d’éviter de perdre des données reçues même si nous prenons quelques millisecondes pour les traiter. J’ai réussi à connecter le ‍port série du Visor à un pilote dans reSpring. Malheureusement, le transfert IR nécessite une réponse⁢ rapide, ce qui est difficile à atteindre avec notre latence. ‍Le transfert fonctionne, mais pas toujours. Le ⁤HotSync fonctionne également,​ même via USB.

LED d’Alerte

Étant donné⁢ que rePalm prend en charge les⁤ LED d’alerte et que certains modèles ⁢de⁣ Visor en sont équipés (Pro, Prism⁤ et Edge), j’ai voulu les relier. Cependant, il n’existe pas d’API‍ publique pour accéder aux LED sur⁣ les appareils Handspring. Après quelques recherches, j’ai découvert que le HAL de Handspring dispose d’une fonction⁤ pour régler l’état de la LED : HalLEDCommand(). Cette fonction fait exactement ⁣ce que je veux, mais⁢ les versions antérieures du HAL de Handspring ne la‍ prennent⁣ pas⁤ en charge, ce qui peut entraîner un plantage. En réalité, ​seuls trois appareils possèdent une⁣ LED,‌ et je peux les⁣ détecter. J’ai ‌donc⁤ opté pour un ⁢accès direct au matériel. Sur le ‌Visor Edge, la LED​ est sur GPIO ‍K4, sur‍ le Pro, c’est K3, et ‍sur le Prism, C7.​ Nous pouvons écrire directement sur ces GPIO, et cela fonctionne comme prévu.

Mise à Jour Logicielle

Je souhaitais⁤ que reSpring⁣ puisse se mettre à jour automatiquement à partir d’une carte SD. Comment y parvenir ? ⁤Le flash dans le STM32 peut être⁣ écrit par du code exécuté sur le STM32, donc cela ne devrait pas ⁢être trop compliqué.⁢ Cependant, quelques complications se présentent : l’ensemble de⁣ PalmOS⁣ fonctionne à partir du flash, ⁢y​ compris les ⁢pilotes ‍pour ⁣divers matériels. Notre ‍couche de communication pour interagir avec le Visor est également intégrée. Pour⁣ effectuer la mise à jour, nous ⁢devons arrêter l’ensemble du système d’exploitation et désactiver toutes les interruptions et pilotes.⁢ Cela semble simple, ⁤mais parmi ces pilotes se trouvent ceux de la carte SD, où se trouve notre mise à jour.‍ La solution ​consiste à copier ‍la mise à jour en RAM⁢ avant de commencer, car la RAM ne ⁤nécessite pas de pilotes. Mais comment afficher la progression à l’utilisateur ? Notre tampon d’affichage n’est pas⁤ réel, et faire afficher cela par ‍le Visor nécessite beaucoup de code et des interruptions fonctionnelles. Il‌ était donc peu probable que cela fonctionne normalement.

J’ai décidé que la meilleure façon de procéder ⁣était de laisser le Visor dessiner l’interface utilisateur de mise à jour lui-même, en utilisant un emplacement SRAM unique pour afficher la progression. Écrire dans un emplacement SRAM est quelque chose que notre processus de mise à jour peut‍ faire sans problème, car la SRAM est simplement mappée en ​mémoire. ​Le reste était simple‌ : un programme​ pour charger la ​mise à jour en RAM, envoyer le message « mettre à⁢ jour maintenant »,⁣ puis flasher la ROM, tout en⁢ écrivant dans l’emplacement SRAM approprié le « pourcentage complété ». Cela a nécessité l’exportation de ⁣l’API « envoyer un message »⁤ du DAL de rePalm pour​ que les applications puissent ⁣l’utiliser. J’ai réalisé cela.

Stockage NAND Intégré

Un Défi avec le⁢ NAND

La⁤ carte reSpring est équipée de 256 Mo⁤ de mémoire flash NAND⁤ sur un bus QSPI. Pourquoi ? À l’époque⁤ de sa conception, je pensais que ce serait intéressant et c’était assez économique. Le NAND est la​ technologie de stockage⁢ sous-jacente​ à la plupart des dispositifs ⁤modernes -​ vos cartes SD, vos SSD et le stockage ‍de votre téléphone. Cependant,‌ le NAND présente des défis : il nécessite des corrections d’erreurs,⁢ car il ⁤peut parfois inverser un ou deux bits. De plus,‌ des ‍inversions de ‌bits peuvent s’accumuler avec le temps, rendant la correction d’erreurs insuffisante, ⁣ce qui nécessite de déplacer les données lorsque cela devient nécessaire. L’unité adressable la ​plus ⁤petite du NAND est une page, qui est⁢ la taille pouvant être lue ou programmée. La ⁢programmation ne fait que changer des bits en zéro, et pour récupérer ⁤des bits, une opération d’effacement est nécessaire, mais cela se⁤ fait par bloc, ce qui ⁣complique‍ la gestion ‍des données.

Gestion des Disques NAND : Défis​ et Solutions

Les dispositifs de​ stockage NAND présentent des ⁤défis uniques en raison de leur structure. En⁤ raison​ de la nécessité d’utiliser des‌ codes​ de correction d’erreurs, et du fait que les bits ne peuvent être inversés que de un à zéro,​ la réécriture des données ​devient complexe. De plus, il existe​ des limites quant au nombre de fois qu’une page peut être programmée avant d’être⁢ effacée. Les pages d’un bloc ‍doivent souvent être programmées ⁢dans un ordre spécifique, et il est également possible que des⁣ blocs deviennent défectueux, ne parvenant pas ‌à ⁤s’effacer ​ou à se⁣ programmer correctement. Il n’est pas rare qu’un appareil NAND soit livré avec des blocs défectueux dès sa sortie d’usine. Cela remet en question l’idée que l’on se fait du stockage par⁣ blocs. La gestion des NAND nécessite une attention particulière pour garantir une utilisation efficace de l’espace de⁢ stockage. Étant donné que ⁣les blocs s’usent à cause des⁢ effacements, il est crucial de répartir uniformément l’usure sur l’ensemble du dispositif, ce qui peut nécessiter le déplacement de données. De plus, des ​coupures de courant peuvent survenir pendant ces opérations, rendant nécessaire une gestion prudente‍ des effacements et des écritures. Maintenir une vision cohérente de ce qui est stocké où est un véritable défi, et c’est là qu’intervient la couche de traduction flash (FTL).

Création d’une FTL

Ayant déjà développé ‌une FTL il y a plus d’une⁢ décennie, j’avais une idée générale du processus. ⁣Cependant, cette fois-ci, j’avais des objectifs clairs. ​La priorité absolue⁣ était de ‌garantir qu’aucune donnée ne soit perdue en cas de coupure ‍de courant aléatoire,⁣ car le module peut être‌ retiré à⁢ tout moment. La⁤ FTL que j’ai conçue est conçue pour ne jamais perdre de données, peu importe le moment où l’alimentation⁤ est coupée. Un autre objectif secondaire était de minimiser l’utilisation de la ⁣RAM, car reSpring ne dispose que de 8 Mo de mémoire vive.

Les pages de la NAND sur reSpring⁣ mesurent 2176 octets. Parmi ceux-ci, 4 sont réservés pour⁣ le « marqueur de‌ bloc défectueux », 28 sont libres d’utilisation sans‌ protection par correction d’erreurs, et le reste est divisé en quatre parties égales de 536 octets, qui peuvent être corrigées par le chip (en utilisant les 16 derniers octets pour le code ECC). Cela‌ signifie qu’à chaque⁣ page, nous avons 2080 octets corrigés par erreur ‍et 28⁣ octets non corrigés. Chaque bloc contient 64 pages, et l’appareil ‌dispose de 2048 blocs, dont au moins 2008 sont ⁢garantis comme étant fonctionnels dès la sortie d’usine. L’utilisation de l’ECC par le chip est avantageuse, car il dispose ⁤d’une ‍unité matérielle spécialisée capable‍ d’effectuer cette tâche beaucoup plus rapidement que notre CPU ne ‍pourrait le ‌faire en⁣ logiciel. Il⁢ nous informe également du nombre de bits corrigés à chaque lecture, ce qui est essentiel pour évaluer la​ santé de chaque page et décider quand relocaliser les⁣ données avant qu’elles ne⁢ deviennent illisibles.

Présentation de la FTL comme un Dispositif‍ de Bloc

J’ai décidé⁤ que ma FTL​ se présenterait comme un dispositif de bloc avec des ‍blocs de‌ 4 Ko.⁤ C’est la‍ taille de cluster que FAT16 devrait idéalement utiliser sur notre appareil, et des blocs plus grands permettent de réduire la⁢ taille de la ‍table de​ mappage (la correspondance entre le « numéro de secteur » virtuel et le « numéro de ⁣page » réel). ‍Ainsi, nous traiterions​ toujours deux pages comme une seule. Cela signifie que⁣ chacune ‍de nos⁢ pages virtuelles contiendrait 4160 octets de données corrigées ⁤par erreur et 56 octets de​ données non corrigées. Étant donné que ‌notre flash permet d’écrire la même page deux fois, nous utiliserons la zone non corrigée pour stocker des données persistantes,​ telles que le nombre d’effacements de ce bloc, ainsi que‌ pour les⁤ blocs précédents et suivants, et un compteur de génération pour déterminer l’ancienneté des informations. L’ECC fait ‍maison était simple :‍ un code‌ de Hamming pour corriger jusqu’à un⁣ bit ⁤d’erreur, et ensuite répliquer l’information et le code de Hamming trois fois. Cela devrait fournir une protection suffisante. Comme cela n’utilisait ⁣que la partie non corrigée des pages,⁤ nous pouvons facilement écrire des données corrigées par erreur par-dessus sans problème. Chaque fois ‍que nous effaçons une page, nous écrivons immédiatement ces données. Si nous sommes interrompus, les ⁢pages‌ environnantes ⁢contiennent les informations nécessaires pour reprendre l’écriture après le retour de l’alimentation.

Gestion​ des Données et Points de Contrôle

Les données corrigées par⁤ erreur contiennent les données utilisateur (4096 octets)​ ainsi que nos données de service, telles que le secteur virtuel associé, le compteur de génération, des informations sur ce bloc et quelques blocs voisins, ainsi que d’autres ‌informations. ⁢Ces données nous permettent de ⁤reconstruire la table ⁢de mappage après un cycle d’alimentation. ⁤Cependant, lire l’intégralité de l’appareil à chaque mise sous‌ tension est lent et peu pratique. Nous avons⁢ donc mis en place des points de contrôle.‌ Chaque ​fois que l’appareil est éteint ou que la FTL est démontée, nous écrivons‍ un point de contrôle. Celui-ci contient les‍ données de mappage et d’autres informations qui nous permettent de reprendre rapidement⁢ l’opération sans avoir à scanner l’intégralité ​de l’appareil. Bien‌ sûr, en cas de coupure de courant inattendue, un scan⁣ est ⁣nécessaire. Pour ces cas,⁤ une optimisation‌ a été mise en place : un répertoire à la fin de chaque bloc indique son contenu, ce qui permet de lire seulement 1/32 de l’appareil⁤ au lieu de 100 %, offrant ainsi un gain de vitesse de 32 fois !

Intégration⁣ avec PalmOS

Les⁤ requêtes de lecture et d’écriture de PalmOS se traduisent directement par des opérations de lecture et d’écriture de la couche FTL. Cependant, un problème se ‌pose : PalmOS ne prend en charge que ⁢des dispositifs de bloc ⁤avec des tailles de secteur de 512 octets. J’ai donc développé une couche de traduction ‌simple ⁣qui effectue des ⁤opérations de lecture-modification-écriture selon ‌les besoins pour mapper mes secteurs ⁣de 4 Ko ⁤aux secteurs de 512 octets de PalmOS, si​ la demande de PalmOS ne s’aligne pas parfaitement avec les secteurs de 4 Ko de⁣ la FTL. Cela n’est pas aussi complexe ou lent que l’on pourrait le penser, car PalmOS utilise⁣ FAT16⁢ pour formater l’appareil. Lorsqu’il le fait, il⁣ interroge l’appareil sur sa taille ⁢de bloc préférée.​ Nous répondons avec 4⁣ Ko, et à partir⁣ de‌ ce moment, le⁤ pilote FAT de PalmOS n’écrit que des clusters de 4 Ko complets, qui s’alignent parfaitement avec ​nos‍ secteurs de 4 Ko de la FTL. L’utilisation de mémoire à l’exécution⁤ de la FTL n’est que de 128 Ko, ce qui est plutôt raisonnable, si je puis me permettre de le dire !‍ J’ai conçu une série de tests rigoureux pour la FTL et les ai exécutés sur mon ordinateur pendant plusieurs nuits. Les tests⁤ simulaient des défaillances​ de données, des coupures⁤ de courant aléatoires, etc. La FTL a réussi. ⁤Il ⁣y a en réalité beaucoup plus de détails‍ concernant cette FTL, et vous êtes libre d’explorer ‌le code source pour en savoir plus.

Un Dernier Détail Surprenant

Malgré tout ce⁣ travail, rePalm fonctionnait plutôt bien dans l’ensemble. Cependant, il arrivait parfois qu’un message soit perdu entre le Visor et le module, ou vice-versa. Après de‍ nombreuses heures de débogage, j’ai fait une découverte surprenante. La SRAM à double port ne prend pas en charge l’accès simultané à‍ la même adresse par les deux ⁤ports. ⁢Cela est documenté dans sa‌ fiche ⁤technique comme une « fonctionnalité utile », mais ce n’est en réalité pas le cas. Il pourrait être raisonnable d’interdire deux écritures simultanées sur ⁤le même mot, mais deux lectures devraient fonctionner, tout comme une lecture et une écriture (avec une lecture retournant​ soit l’ancienne, ​soit la nouvelle⁤ donnée, ou ‍même un mélange des deux). Cette SRAM‍ signale ​plutôt « occupé » à un côté. Étant donné qu’elle ne devrait jamais être occupée, et que le slot Springboard n’a même‍ pas de broche BUSY, ces signaux n’étaient reliés à rien. C’est dans une note de bas de page du manuel‌ que j’ai trouvé cette information. Il⁣ était indiqué que⁣ passer la puce en mode SLAVE et élever les⁣ broches BUSY​ (qui sont désormais des entrées) à un niveau élevé permettrait un accès simultané. Cela fonctionne en partie. Il n’y a plus de signalisation d’occupation, mais parfois une écriture sera PERDUE si elle est exécutée en même temps qu’une⁣ lecture. De plus, une lecture renverra ⁢parfois ZÉRO si elle est exécutée⁤ en même​ temps qu’une autre lecture ou écriture, même si⁣ les anciennes et nouvelles données n’étaient pas toutes deux nulles. Il semble qu’il n’y ait pas de ​solution à ce problème. Une autre entreprise proposant ⁣de ‌la SRAM à double port avait la même limitation, ce qui me fait penser qu’aucun fabricant dans l’industrie ne produit de véritables SRAM à double port. Cette SRAM dispose de ce que ‌l’on appelle des « sémaphores », qui ‍peuvent être utilisés pour mettre‍ en œuvre‌ de véritables sémaphores partagés par les deux dispositifs, mais autrement,​ ce ⁢n’est ⁢pas une véritable RAM à double port. Dommage !

Utiliser ces sémaphores nécessiterait un câblage significatif : il​ faudrait une⁢ nouvelle​ ligne de sélection de puce pour⁤ cette puce‌ et ⁤inventer un nouveau moyen d’interrompre⁤ le STM, car la seconde ligne de ⁣sélection de puce serait désormais utilisée pour accéder aux sémaphores. Cela dépassait mes capacités⁢ de reconfiguration, donc j’ai simplement renforcé le protocole pour éviter ces problèmes.⁣ Désormais, le ⁣STM écrira chaque mot de données qui ⁣pourrait être lu simultanément 64 fois, puis le relira‌ pour ‌vérifier qu’il a été écrit.‌ Le protocole de ‌communication a également été modifié pour ne jamais utiliser de zéros, de sorte que si un ⁣zéro est détecté, il est clair qu’une nouvelle lecture est nécessaire. Grâce à ces ajustements,‍ la communication est stable,⁤ mais lors de la prochaine révision de la carte, je pense que des améliorations supplémentaires seront nécessaires.

Technologie :‍ Un matériel plus ⁣authentique

rePalm-MSIO

technologie rePalm-MSIO première carte

Après avoir analysé le protocole Sony MemoryStick, une idée⁤ a émergé : pourquoi⁤ ne pas créer une ⁤version rePalm sur un ⁢MemoryStick ? En théorie, il serait possible de faire fonctionner un microcontrôleur ⁣comme un appareil MemoryStick, de charger un programme sur ⁤l’appareil hôte PalmOS de Sony, puis ⁣de‌ le contrôler, à l’instar de ce que faisait reSpring. C’était⁤ l’objectif, bien sûr. L’espace est restreint⁤ et les exigences de synchronisation sont ⁤extrêmes. ⁣Le⁤ fait que ⁤le protocole MemoryStick soit⁢ si différent des bus normaux ‍signifie qu’il n’y aura pas de ​solutions simples. Cependant, j’étais déterminé à faire fonctionner ce projet.

Choix ‍du microcontrôleur

Utiliser‌ un STM32F429 avec une puce SDRAM prendrait‍ trop de place pour s’insérer dans un slot MemoryStick. J’ai donc opté pour un chip STM32H7 à 64 broches. Ce‍ dernier dispose de 1,25 Mo ⁣de RAM interne, ce qui est un peu juste⁤ pour PalmOS. Heureusement, il prend en charge une interface QSPI‍ en‍ lecture/écriture, ce qui est parfait ⁢pour interagir avec des puces PSRAM⁢ QSPI comme ⁣l’APS6404L d’APMemory ! Cela permet d’avoir 8 Mo de⁢ RAM sans occuper beaucoup d’espace sur la carte ​ni nécessiter un grand nombre de broches. Le ⁣STM32H7 ​est également un Cortex-M7, offrant une ‍amélioration significative par rapport au cœur Cortex-M4 du STM32F429. ⁣Le M7 est plus rapide par cycle et ​dispose d’un cache !​ Le fait que le STM32F429 n’ait pas de cache était un ⁢handicap sérieux lors de l’exécution ‍de code⁤ depuis la RAM, car‌ celle-ci était limitée à⁤ la moitié de la fréquence d’horloge du cœur. Avec un ensemble de travail suffisamment petit, le M7 peut fonctionner à pleine vitesse⁢ depuis le cache ! De plus, il y​ a le TCM, une mémoire‍ proche du cœur qui‍ fonctionne toujours⁣ à pleine ⁤vitesse sans délai ni états d’attente !

J’ai conçu la carte pour qu’elle s’insère dans le ‌slot MemoryStick.⁢ Il s’agit d’une carte à ​4 couches (qui est apparemment ⁢très abordable ‍maintenant). Cela facilite le routage‍ et‍ améliore l’intégrité du signal. Avec l’épaisseur de‍ carte ‍appropriée, il y ​a juste assez d’espace pour⁤ que⁣ les⁢ puces s’adaptent. Tout fonctionne, ⁣s’insère, clique, ⁤tout ! C’est assez ​incroyable, en fait. Bien sûr, il y a eu ‌des erreurs, mais lors de la deuxième révision de la carte, il n’a fallu⁣ qu’un‌ seul fil de contournement,⁣ comme vous pouvez le voir sur la photo. La carte est exactement de‌ la taille d’un ⁣MemoryStick. Il⁣ y a un surplus qui dépasse, ce sont les en-têtes de débogage et ils sont détachables. J’en ai un ‌que j’ai détaché et il est⁢ incroyable de voir à quel point il s’adapte bien à l’intérieur.

Les problèmes rencontrés…

Évidemment, étant donné qu’il s’agit⁤ d’une ⁤puce STM, des bugs sont apparus. La puce se bloquait parfois complètement lors de l’exécution ⁤depuis la‍ RAM QSPI. Lors⁣ d’une consultation, ‌ST a suggéré de modifier les paramètres‍ de l’MPU pour​ rendre la⁣ RAM QSPI non mise en cache. C’est une ⁢suggestion absurde,‍ car même‍ si cela fonctionnait​ (spoiler : ça ne fonctionne pas), cela rendrait⁢ cette RAM tellement lente qu’elle deviendrait inutile. Quoi qu’il ⁣en ⁢soit, lorsque j’ai essayé cela, la RAM s’est corrompue. J’ai vérifié avec des ​traces⁣ de bus ‌et l’ai présenté​ à STM. ils ont admis que toute écriture sur l’interface ⁣QSPI qui n’est pas séquentielle et de taille mot entraînerait une corruption. Cela me dit clairement quel était le seul test qu’ils avaient jamais effectué sur ce‌ périphérique. Quel ⁤désespoir…

Heureusement, avec le cache activé, l’éviction de la ligne de cache sale écrira toujours un nombre entier de mots de manière séquentielle, ​donc il y a de l’espoir. Malheureusement, la puce fonctionnait⁢ un moment, puis se bloquait.​ Ce blocage était très étrange,⁢ mon débogueur ne pouvait‌ pas se connecter au cœur dans cet état, mais il pouvait accéder au port d’accès de ‌débogage lui-même. Cela m’a amené à croire que‍ ce n’était pas le cœur qui se bloquait, mais le tissu interne AHB. J’ai pu le confirmer en me connectant⁢ à un autre port d’accès de débogage (celui sur AHB3), où je⁤ pouvais explorer mais n’avais pas accès aux bus⁣ AHB principaux. STM n’avait pas d’idées.

En tenant compte de ce que je ⁣savais sur ⁤le fonctionnement des ​bus AHB, ‌j’ai formulé des hypothèses sur la manière dont ST avait probablement conçu les arbitres et comment ils avaient câblé leur unité QSPI. J’ai ⁣deviné le problème et trouvé un contournement qui pourrait fonctionner. Après quelques⁣ prototypes, je peux confirmer que cela fonctionne. Le ‍coût en performance est d’environ 20 % (par rapport à l’absence de contournement), mais au moins, il n’y a plus de blocages. ⁢Pourquoi suis-je‍ si prudent sur ce contournement⁣ ? Eh bien, tout en niant l’existence du‍ problème, STM a demandé les détails ⁣précis de mon contournement une fois qu’ils ont⁢ appris que⁢ j’en avais trouvé un. Apparemment, un client réellement​ important ⁣a également rencontré ce problème. ‌Je refuse actuellement de divulguer le contournement tant ​qu’ils n’acceptent⁢ pas d’admettre le problème. Jusqu’à ‌présent, c’est une impasse, ce qui est ‌acceptable – je ne⁣ perds aucune vente à cause de cela. Et eux… ?

Niveau bas de‌ MSIO

Le signal principal qui contrôle les phases du ​protocole ⁣est le BS, qui précède toujours la transition d’état réelle d’un cycle, ce qui le rend‌ très difficile à utiliser. Si seulement il n’était pas en avance d’un cycle, ​je pourrais l’utiliser (et son inverse) comme​ sélecteurs de puce ‍et essayer d’utiliser les ⁢unités‌ de bus⁤ SPI matérielles d’une manière⁢ ou⁢ d’une ⁢autre. Après ‌quelques réflexions, une solution est devenue évidente.⁣ Deux ‍bascules feront l’affaire. En faisant passer le ⁤signal BS à travers elles, je peux le ​retarder d’un cycle. Trouver une bascule à double déclenchement sur front négatif⁣ s’est avéré impossible, donc un inverseur a été ajouté, ce qui m’a permis d’utiliser ⁢un SN74LVC74A facilement disponible.

Avec le signal BS⁤ retardé, il pouvait être utilisé​ comme sélection de ⁤puce pour certaines unités SPI. Pour que cela fonctionne, j’ai câblé TROIS‍ unités SPI ensemble. Le premier front du BS déclenche un canal DMA qui active les trois unités SPI : l’une reçoit le TPC, et les deux autres sont prêtes à recevoir les données qui suivent. Nous n’aurons pas le temps de valider le TPC entre-temps, donc nous ⁢préparons l’unité SPI pour le recevoir quoi ⁢qu’il arrive. Cela ne pose aucun problème. Ce premier front du BS déclenche également une interruption logicielle. En supposant qu’il n’y ait pas trop de délais, nous arriverons dans l’IRQ après que le TPC ait déjà été reçu et, ⁤si la transaction est une écriture, les données sont déjà en route. Si nous avons moins de chance, ⁤les données pourraient même avoir déjà été‌ entièrement reçues. À ce stade, nous pouvons valider le ‌TPC et‍ vérifier sa direction. Si‍ c’est une LECTURE, nous devons immédiatement ‌envoyer le motif de handshake, donc nous utilisons l’une des unités SPI pour le faire⁣ maintenant. Pendant ce temps,​ nous trouvons les données⁢ et les mettons en file d’attente ‌pour transmission, ‍en indiquant à ⁢l’unité SPI d’envoyer également le CRC après. Si c’était une ⁣ÉCRITURE, nous avions deux unités SPI recevant les données. L’une copiait les ‍données dans la ‌RAM, l’autre dans l’unité CRC (le STM32H7 ne peut pas calculer le CRC‍ des données entrantes si nous ne connaissons pas à⁣ l’avance la longueur). Nous vérifions rapidement le CRC et configurons l’une des unités SPI pour envoyer ‌le motif de handshake ⁤afin​ d’accuser réception des données.

« Maintenant, tout cela semble très fragile »,⁢ dirait un⁣ observateur avisé. Oui ! Très. Cela signifie également que nous ne pouvons jamais désactiver les interruptions trop longtemps, car il n’y a que quelques⁣ cycles de marge entre l’envoi des données et la ⁣nécessité d’une réponse pour éviter que l’hôte ne dépasse le délai. J’ai dû réarchitecturer ‌un peu la gestion des interruptions du noyau rePalm pour permettre à certaines interruptions de ne JAMAIS être désactivées, en échange de concessions de la part de ces gestionnaires d’interruptions : ils ne font pas d’appels système ni ne‍ modifient un état partagé​ avec ⁢d’autres morceaux de code. Alors, comment interagir avec eux‍ ? Lorsqu’une transaction⁤ MSIO se termine, les⁢ données sont placées dans un tampon partagé, et‍ une interruption ‍logicielle est déclenchée, qui​ est gérée normalement par du code normal avec des contraintes normales. Cela⁢ peut être désactivé, priorisé, etc., car ce n’est plus critique en ‌termes de temps. Bien sûr, tout le code ‍critique en temps doit être exécuté depuis l’ITCM (la mémoire d’instructions étroitement couplée) pour respecter les délais.

Lorsque ⁢le STM32H7 fonctionne à 320​ MHz, cela fonctionne la plupart ​du temps avec les nouveaux appareils Palm, car ils exécutent l’interface ⁣MSIO à 16 MHz, ce⁤ qui ‍me laisse un peu de marge. Les appareils plus anciens comme le S500C sont plus difficiles. Ils ⁣fonctionnent avec ⁢le bus MSIO à‌ 20 MHz, et le…

Défis et Solutions de l’Intégration MSIO

Les délais ‍d’exécution sont très serrés. Bien que le système fonctionne correctement, si le cœur du dispositif attend une instruction ‍de ⁣récupération depuis⁤ le‌ QSPI, il ne pourra pas accéder⁣ au gestionnaire d’interruptions tant que cette opération n’est pas terminée, ce qui entraîne une latence accrue. Cela peut parfois retarder le gestionnaire ‍d’interruptions MSIO, le faisant manquer la fenêtre appropriée pour accuser réception d’une transaction. Mon pilote côté ‍hôte effectue des tentatives de reprise pour compenser ce problème. La véritable‌ solution ⁤serait d’utiliser un petit FPGA pour décharger cette tâche du ⁢microcontrôleur principal. Je suis en train ⁢d’explorer cette option.

Vue d’ensemble de MSIO

Technologie rePalm-MSIO ‌fonctionnant sur un PEG-S500C

Étant⁢ donné ⁣qu’il n’existe pas de pilotes MSIO pour rePalm, ⁣j’ai dû les développer moi-même. Mais comment un ‌utilisateur pourrait-il les transférer sur l’appareil ? En théorie, d’après mes recherches en rétro-ingénierie, une MemoryStick ⁣peut avoir plusieurs fonctions, potentiellement ⁣de la mémoire et une ou plusieurs fonctions d’E/S. Aucune telle clé n’ayant ​été observée,‍ j’ai décidé de créer la première. Pourquoi pas ? La logique de fonctionnement est assez simple : la ⁤fonction 0xFF ⁣devrait être dédiée à la ‍mémoire, et tout autre⁤ numéro de fonction⁢ inutilisé pourrait être attribué à l’E/S de rePalm. J’ai choisi le numéro de fonction 0x64. Pourquoi simuler une mémoire⁤ ? Pour ⁣fournir le pilote à l’utilisateur, bien sûr !

Mon code ⁤simule un MemoryStick ​en lecture ⁣seule avec 4 Mo de stockage. Étant donné que les MemorySticks sont des dispositifs NAND bruts, mon code se comporte comme ⁢un modèle parfait ⁢- sans ‌blocs défectueux, sans besoin de correction d’erreurs. ‌Le support ​est⁢ « formaté » ⁢avec FAT12 et contient un système de fichiers plutôt curieux. Pour prendre en charge⁣ TOUTES les⁢ appareils ‌Sony, le⁣ pilote est nécessaire⁤ à plusieurs endroits. Tout appareil avec PalmOS 4.0 ou⁤ version ultérieure affichera les fichiers dans /PALM/LAUNCHER pour l’utilisateur et lancera automatiquement /PALM/START.prc ‌ lors de l’insertion. Les⁤ appareils avec des versions⁢ antérieures de PalmOS ⁣ne permettront à l’utilisateur⁤ de naviguer que dans /PALM/PROGRAMS/MSFILES. Tous⁣ les appareils​ Sony, à l’exception des premiers modèles, avaient‍ également un⁤ autre moyen de lancer⁢ automatiquement un exécutable lors de l’insertion de la clé – ⁣un​ utilitaire Sony appelé « MS ​AutoRun ». Ce ‍dernier ⁣lit un fichier de configuration à /DEFAULT.ARN et‍ charge le programme spécifié en RAM⁣ lors de l’insertion. L’auto-exécution n’est jamais ‌déclenchée si la MemoryStick était déjà insérée au démarrage de l’appareil, ce qui rend cette méthode peu fiable. C’est ⁣pourquoi nous avons besoin que le fichier soit visible et accessible à l’utilisateur pour un lancement manuel. Comptons alors combien de copies ⁤de l’application pilote notre MemoryStick nécessite. Une ⁤dans /PALM/LAUNCHER, une ‌dans /PALM/PROGRAMS/MSFILES, et⁣ une comme /PALM/START.prc. Trois copies. Cela ne suffira pas⁢ ! Si seulement FAT12 supportait les liens durs…

Mais attendez, si le système de ⁢fichiers est en lecture seule, il PEUT ⁢ supporter ‌les liens durs ! Plusieurs entrées de ⁤répertoire peuvent ⁢référencer la même chaîne de clusters.⁤ Cela ne pose problème que lorsque le fichier est supprimé, ce qui ne se⁤ produit pas sur un système de fichiers en⁤ lecture seule. Le système de fichiers⁢ contient donc un répertoire PALM à​ la⁢ racine, qui contient le fichier DEFAULT.ARN, pointant vers un cluster avec⁢ son contenu, un répertoire PROGRAMS, un répertoire LAUNCHER, et une entrée ‌de répertoire​ nommée ⁢ START.PRC ⁣pointant vers le premier cluster de notre pilote. Le répertoire PROGRAMS contient un répertoire ‍ MSFILES, qui lui-même contient une autre entrée de répertoire pointant‌ vers le pilote, nommée⁢ DRIVER.PRC. ‌Le répertoire /PALM/LAUNCHER contient la troisième entrée de‍ répertoire pointant vers le⁣ pilote, également nommé DRIVER.PRC. PalmOS ne réalise‍ pas de vérification du système de‌ fichiers sur les supports⁣ en lecture seule, donc aucun problème ⁢ne se pose – tout fonctionne.

Performance de MSIO

Certains appareils Sony disposent d’une API MSIO exportée dans leurs pilotes MemoryStick, que ⁣j’ai pu rétroconcevoir ⁣(et publier). D’autres n’en avaient pas, mais Sony a publié des mises à jour incluant cette API. Ces ⁤mises à jour​ étaient généralement accompagnées de périphériques MSIO comme l’adaptateur Bluetooth MemoryStick ou la caméra MemoryStick. Certains appareils n’ont jamais eu de support MSIO officiel. Je souhaitais⁣ les prendre tous en charge, et comme j’avais déjà rétroconçu le fonctionnement de la ⁢puce hôte MemoryStick (MB86189), j’ai pu écrire mes propres pilotes, communiquant‌ directement avec elle. Cela a fonctionné pour certains appareils.⁣ D’autres n’ont pas d’accès direct à la puce, car le DSP ‌en prend le contrôle. Le DSP de Sony n’est pas documenté, le firmware est crypté, et la ‍clé ‌n’est‍ pas connue. ‍J’ai été bloqué un moment. j’ai réussi à comprendre juste assez pour pouvoir envoyer et recevoir des TPC bruts via le DSP. Cela a bien ⁢fonctionné sur presque tous les appareils, sauf sur la série ​N7xx. Leur firmware DSP était ⁣le‌ plus ancien de tous (d’après mes ‌informations) et la meilleure bande passante que j’ai pu⁤ en tirer était de 176 Kbit/s. ‌Inutile de dire que ce n’est pas suffisant pour la vidéo en direct (ce​ que rePalm tente de réaliser). Cela fonctionne, mais la ⁢qualité n’est pas optimale.

Étant donné que MSIO permet des transferts de⁣ pas plus de 512 octets⁣ par transfert, ⁣le transfert des données d’image d’écran ​est⁤ complexe. La même ​compression que celle ⁣utilisée dans reSpring est appliquée ici. Même ainsi, la performance varie⁤ en fonction de l’appareil et de la configuration de l’écran. Sur les appareils à faible résolution, tout est rapide. Sur ⁣les appareils à haute résolution (sauf N7xx), 35 FPS est atteignable en mode 16 bits par pixel. C’est ⁤encore plus‍ rapide sur les appareils en niveaux de gris. ⁣Le⁤ seul appareil PalmOS 4 HiRes+ ‌(NR70V) est à la traîne⁣ avec environ 20 FPS.​ Cela est​ dû à la quantité de données à transférer à ⁢chaque image -‍ 300 Ko.

Autres points à considérer

Il est intéressant de noter​ qu’Asus a licencié la technologie MemoryStick de Sony, donc les appareils PalmOS d’Asus (familles s10 et s60)⁤ utilisent également MemoryStick. ⁢J’ai ajouté le support pour eux. Pour chaque appareil, j’ai connecté autant ​que ‍possible à rePalm. ‌Les ​appareils avec une LED ont été reliés au gestionnaire ‌d’attention, et ceux avec un moteur de vibration​ ont également été⁤ intégrés. La gestion du son‌ est ‌un peu plus complexe. Certains ⁢de ces appareils​ avaient un DSP​ pour le décodage MP3, mais la capacité de ⁢jouer des sons échantillonnés bruts est limitée, car le 68K n’était probablement⁢ pas capable de⁤ le faire ‌assez rapidement. Il existe une API Sony pour jouer‍ de l’ADPCM à 8 kHz et 4 bits par échantillon. J’ai envisagé de la connecter à la sortie audio de rePalm, mais⁢ je n’ai pas eu le temps de le faire. Il est probable que cela ‍ne vaille pas la peine,⁣ car la ​qualité serait ​médiocre. J’ai également envisagé une alternative‌ : faire encoder la⁤ sortie de rePalm en⁢ MP3⁢ et trouver un moyen de‌ l’envoyer au DSP, mais j’ai rencontré des obstacles. Dans la ‍plupart des appareils, le‍ firmware DSP lit le ⁢fichier MP3 directement depuis la MemoryStick, contournant complètement le système d’exploitation, ce qui me fait penser que je ne trouverai‍ peut-être pas de moyen⁤ d’injecter des données MP3 même⁣ si ⁤j’y parvenais.

Au⁣ départ, j’ai développé ‌sur le STM32H7B0RB. Cette variante ne dispose que de 128 Ko de mémoire flash, ce​ qui n’est évidemment pas suffisant pour contenir PalmOS. ‌J’ai utilisé ⁣une partie de la RAM pour contenir une image ROM, que je chargeais via SWD à chaque⁢ fois. Cela fonctionnait ⁤assez⁤ bien, mais ce n’était pas⁣ vraiment pratique car cela ne pouvait pas être utilisé⁢ loin⁣ d’un ordinateur. ⁤Heureusement, j’ai pu ‌(avec beaucoup d’aide d’une source anonyme) obtenir certains des puces STM32H7⁤ avec 2 Mo de mémoire flash interne. Cela ‌ EST suffisant pour contenir PalmOS, donc maintenant j’ai⁤ des variantes qui démarrent directement à l’insertion. Les dernières ⁢cartes disposent également d’une mémoire NAND intégrée ​qui sert de dispositif de stockage ‌pour l’utilisateur utilisant mon FTL, mentionné​ précédemment. L’album ⁤photo (lien ci-dessus) contient plus de photos et de vidéos ! Voici une d’elles. Profitez-en !

AximX3

Technologie Axim X3 fonctionnant sous Palm

Ce projet a été un défi amusant, réalisé pour le plaisir. Étant donné ⁣que cet appareil utilise un processeur ARMv5T, j’ai dû adapter mon noyau‌ à⁣ cette architecture. Ce n’était pas très ⁢compliqué ⁢et cela fonctionne maintenant.⁣ Fait ‌intéressant, cet appareil présente des similitudes internes‌ avec le Palm Tungsten T3, ce ⁢qui signifie que cette même⁢ version de rePalm peut ⁣fonctionner avec⁣ peu ⁣de modifications sur le T|T3 ⁢également.

J’ai investi beaucoup d’efforts dans ce dispositif. Heureusement, une grande partie de ⁢l’analyse initiale du matériel avait déjà été effectuée dans le⁣ cadre de ‍mon projet uARM-Palm. Presque tout fonctionne : l’audio entrant et sortant, la carte SD, l’infrarouge, l’écran tactile et les boutons, ainsi‍ que le rapport de batterie. Seuls⁤ l’USB et le mode veille/réveil‍ manquent. ⁣Pour l’USB, je ne vois pas d’intérêt, et le ‍mode veille‌ est compliqué par le bootloader intégré. Les premières versions utilisaient⁣ un chargeur ​WinCE que j’avais écrit pour charger le ROM dans la ‌RAM et exécuter à partir de⁣ là. Une analyse plus approfondie du ROM de l’appareil m’a révélé qu’il existe un bootloader assez complet capable de flasher le ROM de l’appareil à partir de la carte‌ SD. J’ai​ décidé d’exploiter cela, et avec quelques modifications, rePalm peut maintenant être⁤ flashé directement dans le ROM de l’appareil. Oui‍ !

Comment cela fonctionne-t-il ? Le bootloader d’origine⁤ a un mode pour cela. Si un fichier image est placé sur la carte SD sous le nom /P16R_K0.NB0,⁣ en insérant la carte, en maintenant le sélecteur ⁤de ⁤la molette​ et le deuxième ‍bouton d’application,‍ puis en réinitialisant l’appareil, il flashera​ l’image⁤ dans la mémoire flash, juste après le bootloader. Cela peut‍ être utilisé pour flasher rePalm ou pour reflasher​ l’image d’origine. Selon la version de ⁤l’AximX3 (il y en a trois),⁣ la ⁤quantité de mémoire flash et de RAM ⁤varie. ‍rePalm détecte la​ RAM disponible et l’utilise entièrement !

Carte de Découverte STM32F469

carte STM32F469DISCO exécutant PalmOS

Ceci a été un petit hack​ rapide pour voir PalmOS en action sur un⁢ écran à densité⁢ 3x. Aucun appareil de ce type n’a jamais été commercialisé. La carte ⁤STM32F469DISCOVERY possède un écran de 480×800, ⁣dont 480×720 est utilisé comme un‍ écran à densité 3x avec une zone d’entrée dynamique. Cette carte est équipée d’un‌ écran ‌tactile capacitif, ce qui la rend peu adaptée à ​PalmOS.‌ Les écrans ⁣tactiles capacitifs ne sont pas idéaux pour des frappes précises sur de ⁣petits éléments, ⁤car votre doigt obstrue ⁣généralement ce que vous essayez de toucher. Bien que cet écran soit relativement ⁢grand, cela n’aide pas beaucoup. J’ai ⁤réussi à​ faire fonctionner ‍cette carte suffisamment‍ pour voir ce que cela donne, mais j’ai peu travaillé dessus par la suite. ⁤Seuls ⁢l’écran, le tactile et ⁤la carte SD sont​ pris en charge. De plus, tout comme le⁣ STM32F429, le STM32F469 ne dispose d’aucune mémoire cache, ce qui ‌le⁢ rend plutôt lent lorsqu’il fonctionne à partir ⁣de la ‍SDRAM.

RP2040

Raspberry Pi‌ Pico exécutant PalmOS

C’est possible !

Quelle est la véritable exigence en RAM/CPU pour PalmOS 5 ? Étant donné que rePalm avait un support (du ⁢moins en théorie) pour Cortex-M0, j’ai voulu essayer sur du⁣ matériel‌ réel,‌ car le support avait été testé ⁢auparavant⁤ uniquement sur CortexEmu. Il​ se trouve qu’il existe⁣ une ‍puce Cortex-M0 avec suffisamment de⁤ RAM ⁤: le RP2040, la puce du Raspberry Pi Pico⁣ à 4 $. ⁢J’ai ensuite cherché un écran‌ avec un ‍écran tactile facilement‍ disponible. Il n’y avait pas beaucoup d’options, mais celle-ci semblait convenir. Après quelques investigations, il s’est avéré ⁤que le faire fonctionner correctement et rapidement ne serait pas facile. La solution spéciale du RP2040‍ – le PIO – est venue à la rescousse ! J’ai trouvé un moyen de le faire. J’ai changé les résistances sur la carte de l’écran de « SPI » à « SDIO » pour activer la ‌carte SD, et ⁢j’ai câblé​ la LED pour qu’elle serve de‍ LED d’alarme pour PalmOS. Ce sont les choses ⁤faciles.

Étant donné que ‍ce projet dépend de certains comportements non documentés dans les puces Cortex-M, il était toujours incertain de ce⁢ qui se passerait dans certains⁤ cas.⁣ Par exemple, le Cortex-M3 provoque un UsageFault lorsque vous ⁤sautez à une adresse sans le bit inférieur⁤ défini, indiquant un passage en mode ARM. Que ferait le Cortex-M0 ? Il s’avère qu’il provoque simplement ​un ⁣ HardFault. m0FaultDispatch à ‌la rescousse !⁣ Il est capable de catégoriser toutes les causes d’un HardFault et de les diriger vers ‍le bon endroit. J’ai trouvé une différence avec le Cortex-M3. Lorsque le Cortex-M3 exécute une instruction BX PC, il sautera à l’adresse actuelle plus 4, en mode ARM. Cela diffère de ​ce que font les puces ‍ARMv5 lorsque vous exécutez cette même instruction ‌en mode Thumb. Elles sautent à l’adresse actuelle plus 4, ​arrondie à la ‍baisse au multiple ⁤de 4 le plus proche, en mode⁣ ARM. Cette différence a déjà‍ été gérée par mon code JIT et mon émulateur. Mais le Cortex-M0 fait encore une troisième chose ⁣dans ce cas. Il semble en fait traiter l’instruction comme‍ invalide. Le PC n’est ⁤pas‌ modifié, ⁤le mode n’est pas changé, ‍et un HardFault est pris directement ​sur l’instruction elle-même. Curieusement, cela⁢ ne se produit ‌pas si un autre⁤ registre non-PC⁢ avec le bit inférieur effacé est utilisé.‌ Quoi qu’il en soit, j’ai ajusté le code JIT et l’émulateur pour gérer cela. ‍J’ai également modifié CortexEmu pour émuler cela correctement.

Souvenirs

Le RP2040 ne dispose d’aucune mémoire flash, il⁣ utilise ⁢une mémoire flash externe Q/D/SPI pour le stockage de code⁤ et⁤ de données. Cela est pratique lorsque vous avez beaucoup de ⁢données. Pour rePalm, cela signifie que nous pouvons avoir un ROM aussi ‌grand que la plus grande puce flash que nous⁤ pouvons​ acheter. Le Pi Pico est livré avec une puce de 2 Mo, donc je l’ai ciblée. ​La situation de la RAM ⁢est beaucoup plus serrée. Il n’y a que 264 Ko de RAM. ‌Ce n’est pas ‌beaucoup. Le dernier appareil PalmOS à ‌avoir eu si peu de RAM fonctionnait sous PalmOS ⁣1.0. Mais cela ⁤vaut la peine​ d’essayer. L’une des plus grandes dépenses en⁢ RAM concerne les graphiques. La principale est le framebuffer. PalmOS suppose que l’affichage ​a un framebuffer directement⁣ accessible par le‌ CPU. Cela signifie que si je voulais utiliser l’ensemble de l’écran 320×240 en mode vrai couleur, le framebuffer occuperait 150 Ko. Ouf ! Eh bien, combien est acceptable ?

Après quelques expérimentations, pour démarrer avec succès et lancer le lanceur, ⁣l’application⁤ de préférences ‌et le panneau de calibration du numériseur, ⁢environ 128 Ko⁤ de RAM dynamique⁣ sont nécessaires.​ Les diverses bases de données par défaut ainsi que les bases de données temporaires PACE ⁢dans le tas⁤ de stockage nécessitent un tas de stockage d’au moins 50 Ko. Une taille minimale de tas ⁤de stockage de 64 Ko‍ est vraiment​ préférée, afin ⁢de ne pas manquer d’espace immédiatement au démarrage. Et ⁢le DAL de rePalm nécessite au moins 15 Ko de ‍mémoire pour ses ⁤structures de données et environ 24 Ko pour‌ le tas du noyau où les piles et diverses autres structures de ⁤données sont allouées. Additionnons tout cela. La somme‌ est⁢ de ​231 Ko. Cela laisse au maximum 33 Ko ‍pour le framebuffer. ⁢Il y a quelques options. Nous pouvons utiliser tout l’écran ​à 2 bits par pixel (4 niveaux de gris).⁣ Cela nécessitera un framebuffer de 18,75 Ko. Nous pouvons utiliser un écran carré⁤ de 240×240​ à 4 bits par pixel, ⁣pour un framebuffer de 28,125 Ko. Nous pouvons également utiliser la résolution standard​ à faible densité de 160×160 à un ‌impressionnant 8 ⁢bits par pixel (la seule option non niveaux de gris).

On peut‌ remarquer que les zones de mémoire⁢ ci-dessus n’incluaient‍ pas un ​cache de traduction ‍JIT. C’est exact. Bien que mon JIT prenne‌ effectivement ​en charge le ciblage du Cortex-M0,⁣ il n’y a tout simplement ⁢pas assez d’espace pour que cela en ‌vaille ⁣la peine. ⁢J’ai plutôt activé le⁢ cœur d’émulateur ⁤ARM asmM0 car il n’a besoin d’aucun espace supplémentaire. Ce n’est pas idéal, mais tant pis. Nous savions depuis ⁤le début ‌que des compromis seraient⁢ nécessaires ! Tant que je montre,⁢ faisons⁣ en sorte d’avoir une expérience plein écran, avec une zone d’entrée⁣ dynamique et tout ⁤! 320×240, ‍c’est⁤ parti‍ ! Le deuxième cœur‌ du RP2040 n’est‍ pas encore utilisé.

PACE à ⁢nouveau

Mon PACE patché ciblant ‍le Cortex-M3 mentionné précédemment n’est d’aucune utilité sur un Cortex-M0. Combiné au fait​ que ​je ⁤ne peux ⁢pas utiliser le JIT signifie‍ que tout⁢ le code 68K sera…

Fonctionnant sous une double émulation​ (68K⁤ émulé par ARM, ARM lui-même émulé en mode Thumb), il était temps de développer un tout nouvel‍ émulateur 68k, bien sûr en langage d’assemblage Thumb-1. Je vous présente PACE.m0. Cet émulateur se révèle ⁢assez rapide, rivalisant efficacement avec‍ le PACE ARM de Palm en termes de performance, comme l’a prouvé mes ⁣tests sur mon Tungsten T3. Cela a grandement contribué à ‍rendre la ​version RP2040 utilisable, atteignant désormais une ‍vitesse comparable à celle d’un Tungsten T.

État des lieux technologique

Il reste encore beaucoup à accomplir : intégrer le Bluetooth, le ‌WiFi, l’USB, peaufiner le⁣ débogage de NVFS, et probablement‍ bien d’autres tâches. Néanmoins, je mets à disposition quelques images préliminaires à‍ tester, si vous‌ possédez une ​carte de découverte STM32F429, un AximX3 ou un Raspberry Pi Pico avec l’écran adéquat. Notez ⁢qu’il n’y ⁤a pas de support pour l’USB. Si vous souhaitez expérimenter, voici le lien : LINK. Je poursuis également mes ‍travaux sur les ‌options matérielles reSpring/MSIO, et il se pourrait que vous puissiez bientôt mettre la⁢ main sur l’un d’eux :)⁣ Si‌ vous avez déjà un ⁣module ⁤reSpring (vous savez qui vous êtes), l’archive mentionnée⁣ ci-dessus ⁤contient une mise​ à jour vers la version 1.3.0.0 pour vous également.

Code source technologique

Introduction au code source

Le téléchargement de la version ‍0000 du code source est⁤ disponible ici. Il s’agit d’une ‌version très précoce du code source, destinée à ⁢permettre aux utilisateurs ‌d’explorer‌ cette base de code et de comprendre ‌sa structure. Le fichier README‍ explique l’organisation des répertoires, et un⁢ document​ de licence se trouve dans ⁢chaque répertoire. Pour construire ce projet, il est nécessaire de disposer d’une version moderne (c’est-à-dire la mienne)‍ de PilRC (inclus) ainsi que d’une chaîne d’outils ARM cross-gcc. Certaines constructions nécessitent également une chaîne d’outils ‍68k spécifique à PalmOS, que vous ⁤pouvez trouver ⁤ici, par exemple.

Principes de construction

Créer une image fonctionnelle est un⁢ processus en plusieurs étapes. Tout d’abord, il faut construire ⁣le ‍DAL. Cela se fait en exécutant make dans ⁤le répertoire ​ myrom/dal. Certains paramètres doivent y être passés. Par exemple,⁢ pour ⁣construire pour rPI-Pico avec l’écran Waveshare, la commande make BUILD=RP2040_Waveshare suffira. Dans certains cas, il sera nécessaire de modifier le makefile. Pour la construction​ mentionnée ci-dessus, par exemple, nous ne souhaitons pas utiliser le JIT, préférant l’émulateur à‍ la place. Pour ‍ce faire, il faudra commenter la ligne ENABLE_JIT =yes et décommenter celle⁢ qui indique EMU_CORE =asmM0. Cela générera le fichier DAL.prc. L’étape suivante consiste à créer‌ une image ROM complète. Cela se fait depuis le ⁣répertoire⁤ myrom. Encore une ⁣fois, make est utilisé. Les paramètres à spécifier sont le type de construction (qui ​détermine les paramètres de l’image ROM) et le répertoire ⁤des fichiers à inclure dans la ROM. Pour la ⁣construction RP2040_Waveshare, la commande appropriée est make RP2040_Waveshare FILESDIR=files_RP2040_Waveshare. Le répertoire de fichiers donné​ contient déjà d’autres éléments de⁢ rePalm, tels que PACE et le panneau⁤ de préférences d’informations ‍rePalm.

Construction de PACE

Le patch‌ PACE est un ⁤patch binaire appliqué à PACE. Sa construction se fait⁣ en plusieurs étapes. Tout d’abord, le patch lui-même est assemblé en ⁣exécutant make dans le répertoire myrom/paceM0. Cela produira le patch‍ sous forme ​de fichier « .bin ». Ensuite, en utilisant l’outil patchpace (que vous devez également construire), ‌vous pouvez appliquer ce patch à un fichier PACE.prc non modifié (une copie de celui-ci peut être trouvée, par exemple, ⁤dans le répertoire AximX3). Ce⁣ PACE patché⁢ peut maintenant‌ remplacer la version d’origine dans ⁣le répertoire des fichiers de destination.

Historique des mises à jour de⁣ l’article ‍technologique

  1. La version de l’image ci-dessus a été mise à jour vers v00001 :⁢ le JIT est désormais activé​ (beaucoup plus rapide), l’RTC fonctionne (temps), un bloc-notes a été ajouté, et ‍la ‌réponse tactile a été améliorée.
  2. La ⁣version​ de l’image ci-dessus ​a été mise⁢ à jour vers v00002 : la​ zone de graffiti est maintenant dessinée, le graffiti fonctionne, et plus d’applications ont été ajoutées (Bejeweled a été retiré pour des raisons d’espace).
  3. La version ⁢de l’image ci-dessus a été mise à jour vers v00003⁣ : la ROM est maintenant compressée pour permettre l’inclusion ⁤de plus de contenus. Cela est acceptable puisque nous la décompressons en ⁤RAM de toute façon. Des travaux ont été réalisés‌ sur le support de la carte SD.
  4. Explication de la traduction des instructions LDM/STM.
  5. Rédaction d’une‍ section sur ​le support de la carte SD.
  6. Rédaction d’une section sur ⁢le support du port série.
  7. Rédaction d’une ‌section sur le support de la vibration et des LED.
  8. Rédaction ⁢de ⁢la première partie sur les pilotes ‌NetIF.
  9. La version de l’image ​ci-dessus a été mise ‌à jour vers v00004 : certains problèmes de dessin ont été corrigés (soulignement sous le ⁤champ de texte du bloc-notes), la LED d’alerte fonctionne maintenant, et la carte SD fonctionne (si‌ vous la connectez à la ‍carte).
  10. La version⁤ de l’image ci-dessus⁢ a été mise à jour vers v00005 : un certain support⁤ pour les écrans de ⁢densité 1.5 fonctionne, donc ​l’image utilise désormais⁤ tout l’écran.
  11. Rédaction de la section documentaire sur le support des écrans de⁤ densité 1.5.
  12. Rédaction de la section documentaire ⁤sur le support DIA et téléchargement de l’image v000006 avec cela.
  13. Rédaction⁣ d’une section sur PACE, téléchargement de l’image v000007 avec une exécution 68k ​beaucoup plus rapide et ⁢quelques corrections DIA.
  14. Téléchargement de l’image v000008 avec support IrDA.
  15. Rédaction sur le support audio.
  16. Rédaction sur ‌reSpring.
  17. Téléchargement de l’image v000009 avec un support audio préliminaire.
  18. Téléchargement de l’image v000010 avec un nouveau backend ‌JIT et plusieurs corrections ‍JIT.
  19. Téléchargement de l’image v000011 avec un backend JIT amélioré et plus de corrections JIT, ainsi qu’un mise à jour basée sur ‌carte SD. Rédaction sur le backend Cortex-M0.
  20. Rédaction d’une section détaillée sur le matériel reSpring v1 et son état actuel.
  21. Téléchargement de l’image⁤ de découverte STM32F429 v000012 avec des améliorations ​de vitesse significatives et quelques corrections⁢ (graffiti, bloc-notes) !⁤ (cela correspond à rePalm v 1.1.1.8).
  22. Téléchargement des images STM32F429 et, pour la première fois, des ​images reSpring ⁢pour v 1.3.0.0 avec de nombreuses améliorations de vitesse, rédaction sur le support microphone et le support Zodiac.
  23. 15 avril 2023 : PACE pour M0, mise à jour du matériel rePalm⁤ : MSIO, AximX3, RP2040, nouveaux téléchargements.
  24. 3 septembre 2023 : Code source publié pour ⁣la première fois.
Show Comments (0)
Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *