


Créer un émulateur qui reproduit le bus et la temporisation du vrai matériel
À utiliser pour créer ou corriger un émulateur. Découpe le code par pièce du matériel, reproduit fidèlement bus, temporisation et DMA, teste avec des programmes validés sur machine réelle et garde stables les états sauvegardés et l’API publique.
Pour utiliser ces règles d'IA
## Expliquer le code inhabituel et lancer les vérifications de types et les tests
Écrivez le code de l’émulateur pour des ingénieurs qui ne connaissent peut-être pas le matériel d’origine. Expliquez pourquoi une règle de temporisation, un effet secondaire ou une solution de contournement existe, au lieu de supposer qu’une implémentation inhabituelle s’explique d’elle-même. Ajoutez des liens vers des références matérielles faisant autorité lorsqu’elles éclaircissent le comportement.
Recherchez et utilisez les commandes documentées du dépôt pour le formatage, l’analyse statique, la vérification des types, les tests, les compilations, le mode de surveillance et les tests de performance. Considérez les vérifications obligatoires comme faisant partie de la modification :
- Exécutez le formatage et les tests ciblés pendant les itérations.
- Exécutez la vérification des types lorsque des déclarations publiques ou des limites typées changent.
- Exécutez la suite complète faisant autorité avant de valider les modifications ou de les transférer.
- Exécutez le test de performance pour toute modification importante ou régression de performances présumée.
- Séparez les refactorisations sans rapport d’un correctif ciblé.
Mettez à jour les exemples publics et les références de l’API lorsque des méthodes, options, fonctions de rappel, exportations ou formes d’entrée prises en charge changent. Placez les détails d’implémentation locaux dans des commentaires proches ; réservez les consignes au niveau du projet à l’architecture et aux règles qui s’appliquent à plusieurs composants.
## Découper l’émulateur en composants calqués sur les pièces du matériel
Organisez l’émulateur autour des sous-systèmes matériels qu’il modélise. Utilisez un petit orchestrateur pour coordonner les composants et exposer des fonctions de rappel pour le rendu, l’audio, l’état et les mises à jour de mémoire persistante.
Séparez les responsabilités liées aux processeurs, à la vidéo, à l’audio, au mappage de cartouche ou de mémoire, au chargement de programmes, aux utilitaires de rendu, aux contrôleurs et à la sérialisation. Donnez à chaque composant une interface claire et laissez-le gérer son état interne.
Utilisez l’héritage uniquement lorsque les variantes matérielles partagent un véritable comportement de base et redéfinissent des règles précises de mappage ou de changement de banque. Préférez la composition pour les sous-systèmes indépendants et évitez les accès dissimulés à travers les limites des composants.
Définissez une base de temps commune. Une exécution par image exige toujours un décompte précis des cycles dans chaque image, tandis que les applications hôtes restent responsables de la temporisation de l’affichage et de la planification.
Centralisez la conversion des états sauvegardés au moyen de contrats symétriques de sérialisation et de restauration utilisés par chaque composant avec état.
## Reproduire chaque lecture et écriture du bus, y compris les accès factices
Modélisez le bus comme un comportement avec état, et non comme une simple recherche d’adresse vers une valeur. Le matériel réel peut conserver la valeur la plus récente, renvoyer des données mémorisées depuis des adresses non mappées ou accessibles uniquement en écriture, ou ne piloter que certains bits.
Suivez des registres de rétention distincts lorsque différents bus matériels conservent des états indépendants. Mettez à jour le registre approprié lors de chaque chargement, écriture, opération de pile, lecture de code d’opération et lecture de vecteur d’interruption observable. Lorsqu’un appareil ne pilote qu’une partie d’une valeur, combinez ces bits avec l’état conservé du bus exactement comme le fait le matériel.
Implémentez les lectures et écritures factices comme de véritables opérations du bus. Elles peuvent mettre à jour des valeurs mémorisées et déclencher des effets secondaires d’E/S même lorsque le programme n’utilise jamais la valeur renvoyée.
Encodez explicitement la séquence du bus pour chaque mode d’adressage :
- L’adressage indexé peut lire une adresse intermédiaire avant une correction de page.
- L’indexation en page zéro peut lire l’adresse non indexée avant d’appliquer l’index.
- L’indexation indirecte peut lire un pointeur ou une adresse intermédiaire avant d’atteindre l’adresse effective.
- Les instructions de stockage et de lecture-modification-écriture peuvent effectuer des accès factices obligatoires même sans franchissement de page.
- Une instruction de lecture-modification-écriture peut écrire la valeur d’origine avant d’écrire la valeur modifiée.
Préservez l’ordre propre à chaque instruction lorsqu’une lecture se produit avant ou après une opération de pile. Réordonner des opérations qui produisent les mêmes valeurs finales de registres peut néanmoins être incorrect de manière observable sur le bus.
## Synchroniser les périphériques en cours d’instruction et traiter le DMA comme de vrais cycles de bus
Lorsque l’émulateur exécute un composant de manière atomique, mais que le matériel réel fait avancer les composants à l’unisson, un état obsolète peut apparaître lors d’accès aux registres au milieu d’une instruction. Corrigez ce problème à la limite où l’accès devient observable.
Suivez le nombre d’opérations de bus achevées par l’instruction en cours. Avant de lire ou d’écrire un registre d’un appareil synchronisé, faites avancer cet appareil selon le rapport d’horloge exact correspondant aux opérations écoulées. Soustrayez le travail déjà appliqué de l’avancement ultérieur au niveau de l’image afin que le temps ne soit jamais compté deux fois.
Modélisez la création d’un indicateur d’interruption séparément de la livraison de l’interruption. Un contrôle d’inhibition peut empêcher la création d’un indicateur d’état, au lieu de simplement supprimer le signal d’interruption externe. Les tests doivent distinguer ces comportements.
Représentez le DMA comme la prise de contrôle de cycles réels du bus. Un transfert peut modifier la valeur actuelle du bus, retarder la progression du processeur ou changer le résultat d’instructions dont la sortie dépend de l’état du bus. Préservez l’ordre entre DMA, les accès des instructions et les effets secondaires des appareils.
Implémentez les instructions documentées, non officielles ou propres à des cas limites uniquement à partir de références et de tests fiables. Ne simplifiez pas leur comportement par cycle uniquement parce que les logiciels courants ne les utilisent pas.
## Tester avec des programmes connus pour passer sur le vrai matériel
Utilisez plusieurs niveaux de tests, chacun ayant un objectif distinct :
- Les tests unitaires vérifient l’initialisation, la sémantique des instructions, les règles de mappage, la mise en miroir de la mémoire, les transitions d’état et la gestion des erreurs.
- Les tests de régression ciblés figent les tampons d’image, les échantillons audio, les traces de bus ou d’autres sorties déterministes.
- Les bancs d’intégration exécutent des programmes de diagnostic fiables et comparent l’état détaillé de la machine ou les codes d’erreur.
- Les suites de précision matérielle couvrent des interactions que les tests d’instructions isolés ne peuvent pas révéler.
Considérez comme corrects les programmes de référence établis lorsqu’ils sont connus pour réussir sur du matériel réel. Examinez l’émulateur, le banc de test, le montage de test et l’environnement avant d’accuser le programme de référence.
Enregistrez explicitement les échecs acceptés avec une raison précise et limitée. Une liste d’échecs connus n’autorise ni à dissimuler de nouvelles régressions ni à élargir une exception existante.
Testez à la fois les valeurs finales et l’ordre des opérations lorsque le matériel peut observer des accès intermédiaires. Ajoutez un cas de régression chaque fois qu’une correction de la spécification ou qu’un comportement auparavant mal classé modifie l’implémentation.
## Rendre les états sauvegardés entièrement restaurables et arrêter l’exécution après un plantage
Les états sauvegardés doivent inclure chaque composant qui influence l’exécution future, notamment les états du processeur, de la vidéo, de l’audio, du mappeur, du registre de rétention, des interruptions et de la temporisation. Vérifiez que la sérialisation suivie de la restauration reproduit l’exécution, et pas seulement que les données peuvent être analysées.
Exposez la mémoire persistante au moyen d’une fonction de rappel claire ou d’une limite de stockage, au lieu de coupler le cœur à un seul environnement hôte.
Conservez les contrôleurs ordinaires sous forme de machines à états simples, avec des transitions de boutons explicites et des protocoles série. Modélisez les périphériques spécialisés au moyen d’API dédiées qui préservent leurs comportements distincts en matière d’espace, de temporisation ou de détection lumineuse.
Après une exception d’exécution irrécupérable, définissez un état de panne explicite et empêchez toute nouvelle exécution d’image. Exigez une réinitialisation ou un rechargement du programme documentés pour rétablir l’exécution, au lieu de poursuivre à partir d’un état partiellement modifié.
Maintenez stables les entrées de programme acceptées et les types publics de fonctions de rappel. Maintenez les déclarations de types publics avec l’implémentation afin que les consommateurs côté navigateur et côté serveur observent le même contrat d’API.
## Générer les fichiers uniquement par le build et signaler ce qui reste non testé
Générez les paquets de distribution, les fichiers minifiés, les fichiers de correspondance du code source et les déclarations au moyen de la compilation approuvée. Ne modifiez pas directement les sorties générées.
Vérifiez chaque cible d’exécution et chaque format de module que le projet déclare prendre en charge. L’intégration continue doit exécuter les mêmes contrôles de formatage, analyse statique, compilation, types et tests que ceux exigés localement.
Avant de modifier le comportement du matériel, consultez des spécifications faisant autorité et des notes d’implémentation fiables. Documentez la raison d’un code non évident près de l’opération concernée, y compris la conséquence observable d’une modification de son ordre.
Examinez la comparaison finale des modifications pour détecter des éditions accidentelles de fichiers générés, une documentation publique obsolète, des chemins de temporisation non testés et des nettoyages sans rapport. Indiquez les vérifications ciblées exécutées, les résultats des tests de performance le cas échéant, les échecs connus et tout chemin matériel qui reste non vérifié.
