Je ne savais pas comment fonctionnaient les processeurs, alors j'ai écrit un simulateur de logiciel


Il y a quelques mois, j'ai été soudainement frappé par la pensée que je n'avais aucune idée des principes du matériel informatique. Je ne sais toujours pas comment fonctionnent les ordinateurs modernes .

J'ai lu le livre "Mais comment sait-il?" Clark Scott avec une description détaillée d'un simple ordinateur 8 bits: en commençant par les portes logiques, la RAM, les transistors du processeur, en terminant par un dispositif arithmétique et logique et les opérations d'entrée-sortie. Et je voulais implémenter tout cela dans le code.

Bien que je ne m'intéresse pas tellement à la physique des microcircuits, le livre glisse simplement le long des ondes et explique magnifiquement les circuits électriques et la façon dont les bits se déplacent dans le système - le lecteur n'est pas tenu de connaître le génie électrique. Mais les descriptions textuelles ne me suffisent pas. Je dois voir les choses en action et apprendre de mes inévitables erreurs. J'ai donc commencé à implémenter des circuits dans le code. Le chemin était épineux, mais instructif.

Le résultat de mon travail se trouve dans le référentiel informatique simple: une simple calculatrice. Il est simple et il calcule.






Exemples de programmes

Le code du processeur est implémenté comme un terrible tas de portes logiques qui s'allument et s'éteignent , mais cela fonctionne. J'ai exécuté les tests unitaires , et nous savons tous que les tests unitaires sont la preuve irréfutable que le programme fonctionne.

Le code traite l' entrée au clavier et affiche le texte à l'écran à l'aide du glyphe minutieusement conçu pour la police professionnelle, que j'ai appelé Daniel Code Pro . Le seul tricheur: pour prendre l'entrée clavier et sortir le résultat, j'ai dû connecter les canaux via GLFW , mais sinon c'est une simulation entièrement logicielle du circuit électrique.

J'ai même écrit un assembleur grossier qui m'a ouvert les yeux sur beaucoup de choses, pour dire le moins. Il n'est pas parfait. En fait, même un peu merdique, mais il m'a montré des problèmes que d'autres personnes avaient déjà résolus il y a de nombreuses années.

Mais pourquoi fais-tu ça?


«Des adolescents de 13 ans construisent des processeurs dans Minecraft. Appelez-moi quand vous pourrez faire un vrai CPU avec des relais télégraphiques. »

Mon modèle mental du périphérique CPU est bloqué au niveau des manuels informatiques pour les débutants. Le processeur de l'émulateur Gameboy, que j'ai écrit en 2013, ne ressemble en fait pas aux processeurs modernes. Même si l'émulateur n'est qu'une machine à états (machine à états), il ne décrit pas l'état au niveau des portes logiques. Presque tout peut être implémenté en utilisant uniquement l' switch et en maintenant l'état des registres.

Je veux mieux comprendre comment tout fonctionne, car je ne sais pas, par exemple, ce que sont le cache L1 / L2 et le pipelining, et je ne suis pas sûr de bien comprendre les articles sur les vulnérabilités Meltdown et Spectre. Quelqu'un a dit qu'ils optimisaient le code de manière à utiliser le cache du processeur, mais je ne sais pas comment le vérifier, sauf pour prendre un mot. Je ne sais pas exactement ce que toutes les instructions x86 signifient. Je ne comprends pas comment les gens soumettent des tâches aux GPU ou TPU. Et en général, qu'est-ce que le TPU? Je ne sais pas comment utiliser les instructions SIMD.

Tout cela est construit sur une base qui doit être apprise en premier. Cela signifie revenir à l'essentiel et faire quelque chose de simple. Le livre susmentionné de Clark Scott décrit un ordinateur simple. C'est pourquoi j'ai commencé avec ça.

Gloire à Scott! Il travaille!


L'ordinateur de Scott est un processeur 8 bits connecté à 256 octets de RAM, tous connectés via un bus système 8 bits. Il dispose de 4 registres à usage général et de 17 instructions machine . Quelqu'un a créé un simulateur visuel pour le Web : c'est vraiment génial. Ça fait peur de penser combien de temps il a fallu pour suivre tous les états du circuit!


Circuit avec tous les composants du processeur Scott. Copyright 2009-2016. Siegbert Filbinger et John Clark Scott

Le livre vous accompagne tout au long du parcours, des modestes portes logiques aux bits en mémoire et registres, puis continue à superposer les composants jusqu'à ce que vous obteniez quelque chose de similaire au diagramme ci-dessus. Je recommande fortement de lire le livre, même si vous connaissez déjà les concepts. Tout simplement pas la version Kindle, car les graphiques sont parfois difficiles à agrandir et à démonter le «lecteur» à l'écran. À mon avis, il s'agit d'un problème de Kindle de longue date.

Mon ordinateur est différent de la version Scott, sauf que je l'ai mis à jour à 16 bits pour augmenter la quantité de mémoire disponible, car le stockage uniquement des glyphes pour la table ASCII occupe la majeure partie de la machine 8 bits de Scott, laissant très peu d'espace pour le code utile.

Mon processus de développement


En général, le développement s'est déroulé selon ce schéma: lire du texte, étudier des diagrammes, puis essayer de les implémenter dans un langage de programmation à usage général et certainement pas utiliser d'outils spécialisés pour concevoir des circuits intégrés. J'ai écrit le simulateur sur Go simplement parce que je connais un peu cette langue. Les sceptiques peuvent dire: "Bête! Pourriez-vous pas apprendre VHDL ou Verilog , ou LogSim , ou autre chose. Mais à ce moment-là, j'avais déjà écrit mes bits, octets et portes logiques et plongé trop profondément. Peut-être que la prochaine fois j'apprendrai ces langues et comprendrai combien de temps j'ai perdu, mais ce sont mes problèmes.

Dans un grand circuit, un tas de valeurs booléennes sont simplement transmises dans l'ordinateur, de sorte que tout langage compatible avec l'algèbre booléenne convient.

L'application d'un schéma à ces valeurs booléennes nous aide (les programmeurs) à obtenir un sens et, surtout, à décider quel ordre d'octets le système utilisera et à s'assurer que tous les composants transmettent les données sur le bus dans le bon ordre.

C'était très difficile à mettre en œuvre. Pour des raisons de parti pris, j'ai choisi une représentation avec ordre inverse des octets, mais lors du test de l'ALU, je ne pouvais pas comprendre pourquoi les mauvais nombres étaient sortis. Mon chat a entendu beaucoup, beaucoup d'expressions non imprimables.

Le développement n'a pas été rapide: il m'a peut-être fallu environ un mois ou deux de mon temps libre. Mais lorsque seul le processeur a réussi l'opération 2 $ + 2 = 5 $ , J'étais au septième ciel avec bonheur.

Tout s'est déroulé comme d'habitude jusqu'à ce qu'il arrive aux E / S. Le livre a proposé une conception de système avec un clavier simple et une interface d'affichage pour entrer des données dans la machine et produire le résultat. Eh bien, nous sommes déjà allés si loin , cela n'a aucun sens de s'arrêter à mi-chemin. Je me suis fixé comme objectif d'implémenter la saisie au clavier et l'affichage des lettres à l'écran.

Périphériques


Les périphériques utilisent un modèle d'adaptateur comme interface matérielle entre le processeur et le monde extérieur. Il est probablement facile de deviner que ce modèle est emprunté à la conception de logiciels.


Comment les adaptateurs d'E / S se connectent à la fenêtre GLFW

Avec cette séparation, il s'est avéré assez simple de connecter le clavier et l'affichage à une fenêtre exécutant GLFW. En fait, je viens de retirer la plupart du code de mon émulateur et de le modifier un peu pour que les canaux Go fonctionnent comme des signaux d'E / S.

Nous démarrons l'ordinateur




C'est probablement la partie la plus difficile, du moins la plus lourde. Il est difficile d'écrire dans l'assembleur avec un ensemble d'instructions aussi limité, et dans mon assembleur grossier, c'est encore pire, car vous ne pouvez tromper personne d'autre que vous-même.

Le plus gros problème était de jongler avec quatre registres, de les suivre en extrayant des données des registres et de les stocker temporairement en mémoire. Dans le processus, je me suis souvenu que le processeur Gameboy avait un registre de pointeur de pile pour la commodité du chargement et du chargement des registres. Malheureusement, cet ordinateur n'a pas un tel luxe, vous avez donc dû constamment transférer manuellement des données vers et depuis la mémoire.

J'ai décidé de passer du temps sur une seule pseudo- CALL pour appeler une fonction, puis revenir au point. Sans cela, les appels ne sont disponibles que d'un niveau en profondeur.

De plus, comme la machine ne prend pas en charge les interruptions, j'ai dû implémenter un terrible code d'interrogation de l'état du clavier. Le livre discute des étapes nécessaires pour implémenter des interruptions, mais cela complique sérieusement le circuit.

Mais arrête de pleurnicher, j'ai quand même écrit quatre programmes , et la plupart d'entre eux utilisent une sorte de code commun pour le rendu des polices, la saisie au clavier, etc. Ce n'est pas un système d'exploitation, mais il donne une compréhension de ce que fait un système d'exploitation simple.

Ce n'était pas facile. La partie la plus difficile du programme d'écriture de texte consiste à déterminer correctement quand passer à une nouvelle ligne ou ce qui se passe lorsque vous appuyez sur Entrée.

 main-getInput: CALL ROUTINE-io-pollKeyboard CALL ROUTINE-io-drawFontCharacter JMP main-getInput 
Le cycle principal du programme de rédaction de texte

Je n'ai pas pris la peine d'implémenter la touche Backspace et les touches de modification. Mais j'ai réalisé combien de travail le développement des éditeurs de texte nécessite et à quel point c'est fastidieux.

Conclusions


Ce fut un projet amusant et très utile pour moi. Au milieu de la programmation en langage assembleur, j'ai presque oublié les portes logiques ci-dessous. Je suis monté aux niveaux supérieurs d'abstraction.

Bien que ce processeur soit très simple et loin du CPU de mon ordinateur portable, il me semble que le projet m'a beaucoup appris, notamment:

  • Comment les bits se déplacent sur le bus entre tous les composants.
  • Comment fonctionne l'ALU simple ?
  • À quoi ressemble une boucle Fetch-Decode-Execute simple .
  • Qu'une machine sans registre de pointeur de pile et sans concept de pile - suce.
  • Cette voiture sans interruption craint également.
  • Qu'est-ce que l'assembleur et que fait-il?
  • Comment les périphériques interagissent avec un simple processeur.
  • Comment fonctionnent les polices simples et comment les afficher à l'écran.
  • À quoi pourrait ressembler un système d'exploitation simple .

Et maintenant? Le livre dit que personne n'a produit de tels ordinateurs depuis 1952. Cela signifie que je dois étudier le matériel au cours des 67 dernières années. Cela me prendra un certain temps. Je peux voir que le manuel x86 fait 4 800 pages assez longtemps pour une lecture agréable et facile avant le coucher.

Peut-être que je serai un peu choyé avec le système d'exploitation, le langage C, je tuerai la soirée avec le kit de construction PiDP-11 et un fer à souder, puis abandonnerai cette chose. Je ne sais pas, on verra.

Sérieusement, je pense à explorer l'architecture RISC, peut-être RISC-V. Il est probablement préférable de commencer par les premiers processeurs RISC pour comprendre leur origine. Les processeurs modernes ont beaucoup plus de fonctionnalités: les caches et plus, je veux les comprendre. Il y a beaucoup à apprendre.

Ces connaissances seront-elles utiles dans mon travail principal? Peut-être utile, bien que peu probable. En tout cas, j'aime ça, donc ça n'a pas d'importance. Merci d'avoir lu!

Source: https://habr.com/ru/post/fr453158/


All Articles