Je sais que c'est une question très courante. Mais j'ai un angle différent dans mon esprit. Je vais juste essayer de l'articuler ici.
D'après ce que je sais, chaque instruction qu'un CPU exécute est en langage machine et tout ce que le CPU peut faire est de faire des opérations arithmétiques grâce à ALU et à ses transistors (si nous allons au niveau matériel).
Cependant, c'est plus facile à taper qu'à le comprendre. Donc, si tout le CPU ajoute, soustrait, etc., comment un programme, par exemple un programme JAVA disant print Hello World, est-il exécuté avec ces opérations arithmétiques?
Je veux dire comment ce programme est-il converti en quelque chose qui n'est qu'un ajout pour le CPU?
PS Si cette question ne s'applique pas à ce site Web, je m'excuse.
-----Deuxième partie-----
D'accord. Merci à tous d'avoir répondu aussi vite et avec cet enthousiasme. J'ai pensé qu'il valait mieux modifier un peu ma question que d'aller commenter toutes les réponses et les poser à nouveau.
Alors voilà.
Tout d'abord, tous ont répondu spécifiquement à l'exemple de Hello World. C'est ma faute. J'aurais dû garder ce générique. L'exemple de Hello World remet en question les périphériques de sortie et comment son traitement ne se limite pas au processeur, ce qui est évoqué à juste titre dans vos réponses.
Beaucoup d'entre vous ont également remarqué que le CPU fait plus qu'un simple ajout. Je suis d'accord avec ça. Je n'ai tout simplement pas écrit cela et je l'ai supposé jusqu'au bout. D'après ce que je comprends, c'est le processus:
lire l'instruction à partir de la mémoire (en utilisant des bus de données et d'adresses et des trucs de compteur de programmes)
- stocker les données dans un registre à l'intérieur du CPU
- Maintenant, ALU effectue des opérations arithmétiques, bien sûr après le décodage de l'instruction, ou fait un saut si c'est une instruction if like
- Et puis communiquer avec d'autres ressources si nécessaire, comme avec le périphérique de sortie, etc. Les processus au-delà sont triviaux pour l'instant.
Donc à l'étape 3 où le CPU décode une instruction et décide de faire une opération arithmétique (ici, nous supposons qu'il n'y a aucune autre opération à faire comme sauter l'instruction actuelle .. puisque les opérations arithmétiques sont pour la plupart effectuées .. donc nous nous en tiendrons à cela ) C'est là que ma visualisation se termine. Comment une instruction de mon programme n'est qu'une opération arithmétique pour le CPU. Il fait cette opération arithmétique et cette instruction remplit sa fonction.
J'espère que je me suis bien fait comprendre cette fois.
PS Je suppose ici que l'ALU n'est tout simplement pas limité au fonctionnement arithmétique réel que nous faisons dans nos programmes, il exécute plutôt toutes les instructions, qui sont maintenant sous forme binaire, en ajoutant ou en soustrayant etc. pour donner le résultat qu'elles sont destinées produire. Si je me trompe ici, les réponses ci-dessous répondent correctement à ma question.
la source
Réponses:
Vous pouvez essayer de prendre un programme simple et de le compiler en code machine natif. (Java se compile normalement en code JVM, mais Andrew Tennenbaum a un livre où il décrit comment concevoir un CPU qui l'exécute nativement, donc il le fera.) Sur GCC, par exemple, vous donnez le
-S
commutateur au compilateur .Cela vous indiquera que tout ce qui est délicat, comme les E / S, est implémenté en appelant le système d'exploitation. Bien que vous puissiez télécharger la source dans le noyau Linux et faire de même, le problème se passe sous le capot: tout manipule l'état de la mémoire de l'ordinateur, par exemple la liste des processus en cours d'exécution, ou bien parle au matériel en utilisant adresses mémoire spéciales qui le contrôlent ou à l'aide d'instructions CPU spéciales comme
in
etout
sur le x86. En règle générale, cependant, seuls les programmes spéciaux appelés pilotes de périphérique communiqueront avec un matériel particulier et le système d'exploitation enverra des demandes d'utilisation du matériel au bon pilote.Plus précisément, si vous imprimez, "bonjour, monde!" votre compilateur transformera cela en un ensemble d'instructions qui charge la chaîne dans un emplacement particulier (par exemple, en chargeant l'adresse de la chaîne en mémoire dans le
%rdi
registre) et en appelant une fonction de bibliothèque avec l'call
instruction. Cette fonction de bibliothèque peut trouver la longueur de la chaîne avec une boucle, puis appeler l'appel systèmewrite()
pour écrire ce nombre d'octets de la chaîne dans le descripteur de fichier numéro 1, qui est la sortie standard. À ce stade, le système d'exploitation recherche le numéro de fichier de ce processus 1 et décide de ce que cela signifie. Si les écritures sur la sortie standard s'impriment sur votre écran, il y aura un processus comme la copie des octets dans un tampon, qui sera ensuite lu par votre programme de terminal, qui indiquera au système de fenêtrage quelles lettres mettre où dans quelle police. Le système de fenêtrage décide exactement à quoi cela devrait ressembler et dit à un pilote de périphérique de mettre les pixels sur l'écran, ce qu'il fait en changeant la mémoire vidéo.la source
Votre CPU en soi est stupide, comme vous l'avez compris. Mais il y a un microcosme de puces matérielles autour de lui. Vous avez une instruction qui vous permet de définir une ligne du processeur à haut niveau qui est câblée à une autre puce. Cette puce matérielle surveille la ligne et dit: "Hé, si cette ligne est haute, alors je fais quelque chose avec d'autres lignes."
Pour faciliter cela, ces lignes sont regroupées. Certains sont utilisés pour adresser des appareils, certains sont utilisés pour transférer des données pour ces adresses et d'autres encore sont simplement "Mec, il se passe quelque chose d'important dans ma puce".
En fin de compte, votre processeur dit simplement à une autre puce de modifier le signal vers le moniteur pour qu'il ressemble à "Hello World".
Google le dessin d'un affichage à 7 segments. Il a des fils, qui allumeront un segment si vous lui appliquez une tension. Si vous connectez maintenant une ligne de sortie de votre CPU avec une ligne de l'affichage à 7 segments, l'affichage s'allume. Ce n'est pas le processeur qui fait s'allumer la LED, il applique simplement une tension aux lignes, mais d'autres éléments matériels peuvent faire des choses astucieuses à cause de cela.
Si votre CPU définit maintenant toutes les lignes pour le H à haut, le 7 segments affichera H, bien que H ne soit pas un nombre qu'un CPU ajouterait ou soustrait.
Maintenant, si toutes les couches s'accordent sur ce qui est nécessaire pour rendre l'affichage à 7 segments H (définissez 5 lignes spécifiques sur élevé), le compilateur Java peut créer du code pour le faire afficher H. Ceci est bien sûr plutôt gênant - donc les couches commencent d'abstraire. La couche la plus basse commencera par: "Yo, il y a comme 26 lettres, attribuons des nombres à chaque lettre - que diriez-vous de donner à la lettre 'H' le nombre '72'? Ensuite, vous pouvez simplement me dire" Afficher la lettre 72 ", au lieu de "Définir la ligne 309 haut, définir la ligne 310 haut, définir la ligne 498 haut, définir la ligne 549 haut, définir la ligne 3 haut". Et donc chaque couche commence à résumer les informations, comment obtenir certains résultats, donc vous n'avez pas besoin de prendre soin d'eux.
Alors oui, cela se résume à un mappage huuuuge de nombres ou de bits, le CPU peut réellement traiter, à des significations sur lesquelles tout le monde dans la chaîne s'est mis d'accord.
la source
Au collège dans le cadre d'un programme d'études CS, j'ai étudié un exemple étendu de langage de transfert de registre définissant un CPU. J'ai été inspiré pour prendre une approche différente et écrire un simulateur qui accepte une telle notation comme définition, et je l'ai publié dans Embedded Systems Programming (numéro de mars 1989) comme un moyen de répondre au même type de question que vous avez posé, permettant aux gens de construire leur compréhension intuitive de ces choses.
En classe, nous avons continué à distiller cette notation de transfert de résistance dans des portes logiques réelles sur les registres! Il s'écrit: regardez tout ce qui a le registre 'A' comme destination, et le code A = (cas1) ou (cas2) ... et qui s'exprime sous forme de somme de produits ou de produit normalisé normalisé.
Ce n'est qu'à la fin du cours que j'ai appris qu'il s'agissait d'un vrai CPU: le PDP-8 si je me souviens bien.
Aujourd'hui, vous pouvez insérer le diagramme de porte dans une puce de matrice logique programmable.
C'est l'essentiel: un registre est défini avec le résultat des portes ET et OU menant vers d'autres registres. L'une des valeurs à inclure est la valeur de l'opcode.
Imaginez donc: A: = (opcode == 17 & X + Y) | (opcode == 18 & X + Z) | ...
Les processeurs modernes sont plus compliqués, avec des pipelines et des bus, mais des sous-unités individuelles comme une seule ALU fonctionnent de cette façon.
la source
Vous envisagez le CPU ici, mais il y a un autre composant impliqué lors de l'exécution de «Hello World»: l'affichage!
Pour le CPU, une valeur en mémoire n'est qu'un nombre représenté comme un nombre donné de bits (0 et 1).
Comment cela se transforme en lettres à l'écran est une autre histoire: l'affichage a également de la mémoire. Cette mémoire (mémoire graphique) est mappée en «pixels» à l'écran. Chaque pixel est codé avec une valeur: s'il s'agit d'un affichage monochrome très basique, la valeur n'est que l'intensité, pour les affichages en couleur, la valeur est une combinaison de rouge vert et bleu (RVB) qui peut être codée de différentes manières.
Ainsi, lorsque le CPU «écrit» une valeur donnée dans la mémoire d'affichage, les pixels s'allument. Pour réellement écrire des lettres, il faut allumer plusieurs pixels. Généralement, un ordinateur aura un jeu de caractères (en fait plusieurs) défini dans son système d'exploitation. (en faisant l'abstraction des 'polices' elles-mêmes, qui correspond à une définition de ce à quoi chaque lettre devrait ressembler à l'écran)
Ainsi, au fur et à mesure que le code est compilé, il inclut toutes sortes de choses qui proviennent des bibliothèques du système d'exploitation, y compris ces jeux de polices / caractères, etc. qui permettent au CPU de savoir quoi écrire où dans la mémoire graphique. (C'est assez complexe mais c'est l'idée générale: le compilateur inclut beaucoup plus de code que ce qui est dans votre code `` hello world '' seul, via les bibliothèques importées)
En fin de compte, il y a eu beaucoup de choses qui se sont passées comme vous le pensez, mais vous n'avez pas eu à écrire tout ce code.
la source
Voici une approche formelle de votre question dans le domaine de l'informatique théorique.
Fondamentalement, nous pouvons définir un mappage entre le modèle de calcul d'un CPU et d'une machine de turing. Il existe des preuves théoriques que l'ensemble de tous les programmes imaginables de Turing (et donc tous les programmes imaginables exécutables sur un CPU) est dénombrable à l'infini. Cela signifie que nous pouvons identifier chaque programme avec un nombre naturel unique, y compris le programme qui étendrait les nombres naturels aux machines de turing .
Comme vous savez déjà que presque tout ce que les CPU font est des calculs sur les nombres naturels en représentation binaire, vous pouvez penser que les CPU peuvent exécuter tous les programmes imaginables.
Remarque: C'est trop simplifié, mais, à mon avis, donne une belle intuition.
la source
Ce qui peut vous aider, c'est de vous éloigner de votre pensée de «faire de l'arithmétique». Si vous essayez vraiment de creuser ce que les ordinateurs font sous le capot pour imprimer "Hello World", il vaut mieux penser un niveau plus bas. L '"état" de l'ordinateur peut être décrit comme un ensemble de bits, stockés par des commutateurs à transistors qui sont soit allumés ou éteints (ou des condensateurs qui sont soit chargés soit non chargés). L'ordinateur manipule ces bits selon les règles. Les façons dont l'ordinateur est autorisé à manipuler ces bits sont écrites sur le processeur sous la forme de transistors qui font le travail de changement des bits de 0 à 1, ou de 1 à 0.
Quand une ALU "fait de l'arithmétique", cela signifie vraiment qu'elle a changé l'état de l'ordinateur d'une manière qui est cohérente avec nos règles d'arithmétique. Tout ce qu'il a fait, c'est changer quelques bits. C'est le sens derrière le logiciel qui explique pourquoi nous devrions le considérer comme une addition ou une soustraction. Le CPU ne "sait" pas ce qu'il fait. Il change simplement d'état en état, et c'est tout (au moins jusqu'à ce que Skynet prenne le relais).
Quand on y pense de cette façon, des instructions plus compliquées comme une instruction de "saut" ne sont pas différentes. Tout ce qu'il fait, c'est changer quelques bits. Dans ce cas, il se trouve que les bits que nous connaissons signifient l'emplacement de la prochaine instruction à exécuter. Le CPU ne "sait" pas cela, mais nous le savons. Nous utilisons donc l'instruction qui change ces bits pour "sauter" d'un endroit à l'autre dans notre code.
IO n'est vraiment pas différent non plus, c'est juste un changement de bits. La seule différence mineure est que ces bits sont connectés à des transistors qui finissent par éclairer les personnages sur votre écran. Si je peux revenir en arrière il y a quelques décennies, lorsque "Hello World" était en fait simple, il y avait un espace mémoire où, si vous y écriviez des bits correspondant aux caractères ASCII pour "Hello World", ces caractères seraient rendus directement au écran. De nos jours, c'est un peu plus compliqué, car nous avons des cartes graphiques et des systèmes d'exploitation qui dérangent, mais l'idée de base est la même. Vous disposez d'un ensemble de transistors qui sont allumés ou éteints, qui sont liés aux circuits pour afficher un pixel à l'écran. Nous avons défini les bons, et il semble que "Hello World" apparaît à l'écran.
La confusion est simplement une question de syntaxe vs sémantique. Le comportement d'un "moitié ajouté" ou d'un "plein ajouté" dans une ALU est une syntaxe. Il définit les bits qui sortiront lorsque vous en mettrez. La sémantique est le concept de la capacité à faire l'addition. Vous et moi sommes conscients que l'ALU peut "faire des ajouts", mais pour vraiment comprendre ce qui se passe en dessous, vous devez vous rappeler qu'une ALU ne manipule que les bits et octets de la syntaxe.
la source
Les CPU fonctionnent comme ceci:
récupérer l'instruction courante, incrémenter le pointeur "instruction courante".
le décoder (par exemple, savoir ce que cette instruction demande au CPU de faire)
l'exécuter (faire ce que dit l'instruction) - le pointeur d'instruction courant peut être modifié si l'instruction est quelque chose comme un "saut".
Répétez pour toujours
Les processeurs modernes sont plus complexes et essaient de se chevaucher fortement et même de prédire des parties de ce processus (par exemple, commencer à exécuter tandis que 10 autres instructions sont en train de décoder tandis que le processeur va loin devant le pointeur "instruction actuelle" pour garder les "pipelines" pleins), mais le processus essentiel est vraiment le même.
Il existe de nombreux types d'instructions, un exemple de la plupart d'entre elles est:
Instructions de "déplacement". Ceux-ci peuvent copier X vers un autre X, où X est la mémoire (RAM), un registre ou une adresse dans l'espace d'E / S si le CPU prend en charge une telle notion.
Instructions de manipulation de la pile, y compris pop dans le registre, registre push sur la pile, etc. Il s'agit d'un cas spécial d'instructions de «déplacement» qui utilisent et mettent à jour un registre de «pointeur de pile».
Instructions qui effectuent des opérations mathématiques, entre deux registres ou la mémoire et un registre. Ces instructions affectent automatiquement un registre des drapeaux. Un tel drapeau est le drapeau "zéro" qui est positionné si le résultat est nul, un autre est le drapeau "négatif" qui est positionné si le bit le plus significatif du résultat est positionné. Il peut y en avoir d'autres selon le CPU.
Un cas particulier des opérations mathématiques sont les instructions de comparaison, ce qui équivaut à une soustraction, mais le résultat n'est pas conservé. Les drapeaux sont toujours affectés.
Il existe des instructions de branchement qui sautent à une adresse mémoire SI des indicateurs spécifiques sont définis. Rappelez-vous le drapeau "zéro" mentionné ci-dessus? Il sert également d'indicateur "si égal", vous voyez donc des instructions comme
BEQ
sur de nombreux processeurs qui se ramifient en fait si l'indicateur "zéro" est défini.Instructions qui effectuent des opérations logiques (AND, OR, NOT), des bits de décalage et des bits de test. Ils peuvent affecter des indicateurs tels que des instructions mathématiques selon le processeur.
Des instructions qui sautent inconditionnellement.
Instructions qui sautent et enregistrent l'adresse de retour sur la pile (un "appel"), et d'autres instructions qui font sortir une adresse de la pile (un "retour").
Des instructions spéciales comme celles qui arrêtent le processeur, identifient le processeur ou appellent des gestionnaires d'interruption.
"Aucune opération" - presque tous les processeurs ont une instruction "no-op" qui consomme juste des cycles et passe à autre chose.
Ceci est vraiment juste un exemple, il y a des CPU avec moins de types d'instructions et des CPU avec plus.
Le but est d'illustrer qu'il existe de nombreux types d'instructions en plus des instructions mathématiques dans un CPU. Tout dans un langage de niveau supérieur est divisé selon les types d'opérations ci-dessus et seules certaines d'entre elles seront des instructions de type mathématique ou ALU.
la source