A quoi sert un pointeur de stack dans les microprocesseurs?

Je me prépare à un examen par microprocesseur. Si l’utilisation d’un compteur de programme doit contenir l’adresse de la prochaine instruction, quelle est l’utilisation du pointeur de stack?

Une structure de données qui est généralement utilisée pour contenir des frameworks de stack (bits de la stack qui appartiennent à la stack) est une stack de type LIFO (dernier entré, premier sorti – dernière entrée sur la stack). la fonction actuelle).

Cela inclut, mais n’est pas limité à:

  • l’adresse de retour.
  • une place pour une valeur de retour.
  • parameters passés.
  • variables locales.

Vous poussez des objects sur la stack et les éjectez. Dans un microprocesseur, la stack peut être utilisée à la fois pour les données utilisateur (telles que les variables locales et les parameters transmis) et les données de la CPU (telles que les adresses de retour lors de l’appel de sous-routines).

L’ implémentation réelle d’une stack dépend de l’architecture du microprocesseur. Il peut augmenter ou diminuer en mémoire et peut se déplacer avant ou après les opérations push / pop.

Les opérations qui affectent généralement la stack sont les suivantes:

  • appels et retours de sous-programmes.
  • interrompre les appels et les retours.
  • code explicitement en poussant et en écrasant les entrées.
  • manipulation directe du registre SP.

Considérons le programme suivant dans mon langage d’assemblage (fictif):

Addr Opcodes Instructions ; Comments ---- -------- -------------- ---------- ; 1: pc<-0000, sp<-8000 0000 01 00 07 load r0,7 ; 2: pc<-0003, r0<-7 0003 02 00 push r0 ; 3: pc<-0005, sp<-7ffe, (sp:7ffe)<-0007 0005 03 00 00 call 000b ; 4: pc<-000b, sp<-7ffc, (sp:7ffc)<-0008 0008 04 00 pop r0 ; 7: pc<-000a, r0<-(sp:7ffe[0007]), sp<-8000 000a 05 halt ; 8: pc<-000a 000b 06 01 02 load r1,[sp+2] ; 5: pc<-000e, r1<-(sp+2:7ffe[0007]) 000e 07 ret ; 6: pc<-(sp:7ffc[0008]), sp<-7ffe 

Maintenant, suivons l'exécution, décrivant les étapes indiquées dans les commentaires ci-dessus:

  1. C'est la condition de départ où le compteur de programme est zéro et le pointeur de stack est 8000 (tous ces nombres sont hexadécimaux).
  2. Cela charge simplement le registre r0 avec la valeur immédiate 7 et passe à l'étape suivante (je suppose que vous comprendrez que le comportement par défaut sera de passer à l'étape suivante, sauf indication contraire).
  3. Cela pousse r0 sur la stack en réduisant le pointeur de stack de deux, puis en stockant la valeur du registre à cet emplacement.
  4. Cela appelle un sous-programme. Ce qui aurait été le compteur de programme est poussé sur la stack de la même manière que r0 à l'étape précédente, puis le compteur de programme est défini sur sa nouvelle valeur. Ce n'est pas différent d'un push de niveau utilisateur autre que le fait qu'il est fait plus comme une chose au niveau du système.
  5. Cela charge r1 à partir d'un emplacement de mémoire calculé à partir du pointeur de stack - il montre un moyen de transmettre des parameters aux fonctions.
  6. L'instruction return extrait la valeur de l'endroit où le pointeur de la stack pointe et la charge dans le compteur du programme, en ajustant le pointeur de la stack en même temps. C'est comme une pop au niveau du système (voir l'étape suivante).
  7. Popping r0 hors de la stack consiste à extraire la valeur de l'endroit où pointe le pointeur de la stack, puis à ajuster ce pointeur.
  8. L'instruction Halt laisse simplement le compteur de programme où il se trouve, une boucle infinie.

Si tout va bien de cette description, il deviendra clair. La ligne du bas est la suivante: une stack est utile pour stocker l'état dans un mode LIFO et ceci est généralement idéal pour la manière dont la plupart des microprocesseurs font des appels de sous-programmes.

Sauf si vous êtes un SPARC bien sûr, dans ce cas vous utilisez un tampon circulaire pour votre stack 🙂

Mise à jour: Juste pour clarifier les étapes à suivre lors de l'envoi et de la suppression de valeurs dans l'exemple ci-dessus (que ce soit explicitement ou par appel / retour), consultez les exemples suivants:

 LOAD R0,7 PUSH R0 Adjust sp Store val sp-> +--------+ +--------+ +--------+ | xxxx | sp->| xxxx | sp->| 0007 | | | | | | | | | | | | | | | | | | | +--------+ +--------+ +--------+ POP R0 Get value Adjust sp +--------+ +--------+ sp->+--------+ sp-> | 0007 | sp->| 0007 | | 0007 | | | | | | | | | | | | | | | | | | | +--------+ +--------+ +--------+ 

Le pointeur de stack stocke l’adresse de l’entrée la plus récente insérée dans la stack.

Pour pousser une valeur sur la stack, le pointeur de stack est incrémenté pour pointer vers l’adresse de mémoire physique suivante et la nouvelle valeur est copiée dans cette adresse en mémoire.

Pour extraire une valeur de la stack, la valeur est copiée à partir de l’adresse du pointeur de stack et le pointeur de stack est décrémenté, ce qui le pointe vers l’élément suivant disponible dans la stack.

L’utilisation la plus courante d’une stack matérielle consiste à stocker l’adresse de retour d’un appel de sous-routine. Lorsque l’exécution du sous-programme est terminée, l’adresse de retour est affichée en haut de la stack et placée dans le registre du compteur de programmes, ce qui provoque la reprise de l’exécution de l’instruction par le processeur suivant l’appel du sous-programme.

http://en.wikipedia.org/wiki/Stack_%28data_structure%29#Hardware_stacks

Vous avez plus de préparation [pour l’examen] à faire 😉

Le pointeur de stack est un registre qui contient l’adresse du prochain point disponible sur la stack.

La stack est une zone en mémoire qui est réservée pour stocker une stack, c’est-à-dire un type de conteneur LIFO (Last In First Out) où sont stockées les variables locales et l’adresse de retour, permettant une gestion simple de l’imbrication des appels de fonctions dans un programme typique.

Voir cet article Wikipedia pour une explication de base de la gestion de la stack.

Pour 8085: le pointeur de stack est un registre spécial de 16 bits dans le microprocesseur, qui contient l’adresse du haut de la stack.

Le registre de pointeur de stack d’un ordinateur est mis à la disposition des programmes exécutant à des niveaux de privilège inférieurs à ceux des gestionnaires d’interruption. Un ensemble d’instructions dans de tels programmes, à l’exclusion des opérations de stack, stocke des données autres que le pointeur de stack, telles que des opérandes, et similaires, dans le registre de pointeurs de stack. Lors du passage de l’exécution à un gestionnaire d’interruption sur une interruption, les données d’adresse de retour pour le programme en cours d’exécution sont transférées sur une stack au niveau de privilège du gestionnaire d’interruption. Ainsi, le stockage d’autres données dans le registre de pointeur de stack n’entraîne pas de corruption de la stack. En outre, ces instructions peuvent stocker des données dans une partie à gratter d’un segment de stack au-delà du pointeur de stack actuel.

Lisez celui-ci pour plus d’informations.

Utilisation générale d’un registre de pointeur de stack

La stack est une zone de mémoire permettant de conserver des données temporaires. La stack est utilisée par l’instruction CALL pour conserver l’adresse de retour des procédures. L’instruction return RET obtient cette valeur de la stack et retourne à ce décalage. La même chose se produit lorsqu’une instruction INT appelle une interruption. Il stocke dans le Stack le registre, le segment de code et le décalage. L’instruction IRET est utilisée pour renvoyer l’appel d’interruption.

La stack est une mémoire Last In First Out (LIFO). Les données sont placées sur la stack avec une instruction PUSH et supprimées avec une instruction POP. La mémoire de stack est maintenue par deux registres: le pointeur de stack (SP) et le registre de segment de stack (SS). Lorsqu’un mot de données est poussé sur la stack, l’octet de 8 bits d’ordre élevé est placé dans l’emplacement SP-1 et l’octet de 8 bits faible est placé dans l’emplacement SP-2. Le SP est alors décrémenté de 2. Le SP ajoute au registre (SS x 10H), pour former l’adresse mémoire de la stack physique. La séquence inverse se produit lorsque des données sont POPPED provenant de la stack. Lorsqu’un mot de données est POPPED de la stack, l’octet de 8 bits d’ordre élevé est obtenu à l’emplacement SP-1 et l’octet de 8 bits faible est obtenu à l’emplacement SP-2. Le SP est ensuite incrémenté de 2.

Le pointeur de stack conserve l’adresse en haut de la stack. Une stack permet aux fonctions de transmettre des arguments stockés sur la stack et de créer des variables de scope . La scope dans ce contexte signifie que la variable est extraite de la stack lorsque le cadre de la stack est parti, et / ou lorsque la fonction retourne. Sans stack, vous devez utiliser des adresses de mémoire explicites pour tout. Cela rendrait impossible (ou du moins sévèrement difficile) de concevoir des langages de programmation de haut niveau pour l’architecture. De plus, chaque mode de processeur a généralement son propre pointeur de stack en banque. Ainsi, lorsque des exceptions se produisent (interruptions par exemple), la routine du gestionnaire d’exceptions peut utiliser sa propre stack sans altérer le processus utilisateur.

Si vous avez envie d’une compréhension plus profonde, je recommande vivement Patterson et Hennessy en tant qu’introduction et Hennessy et Patterson en tant que texte intermédiaire à avancé. Ils sont chers, mais vraiment pas pareils; Je souhaite juste que l’un ou l’autre soit disponible lorsque j’ai obtenu mon diplôme de maîsortingse et que je suis entré sur le marché du travail en concevant des puces, des systèmes et des parties de logiciels système (mais, hélas! Les pointeurs de stack sont tellement cruciaux (et la distinction entre un microprocesseur et tout autre type de processeur si significative dans ce contexte … ou, dans tous les autres contextes, au cours des dernières décennies …! -) que Je doute de quelque chose, mais quelques rafraîchissements approfondis peuvent aider! -)

Sur certains processeurs, il existe un ensemble de registres dédié à la stack. Lorsqu’une instruction d’appel est exécutée, un registre est chargé avec le compteur de programme en même temps qu’un second registre est chargé avec le contenu du premier, un troisième registre est chargé avec le second et un quasortingème avec le troisième, etc. Lorsqu’une instruction de retour est exécutée, le compteur de programme est verrouillé avec le contenu du premier registre de stack et à la même heure que ce registre est verrouillé à partir du second; ce deuxième registre est chargé à partir d’un troisième, etc. Notez que ces stacks de matériel ont tendance à être plutôt petites (beaucoup de micros de séries PIC plus petites, par exemple, ont une stack à deux niveaux).

Bien qu’une stack de matériel présente certains avantages (par exemple, les commandes push et pop n’ajoutent pas de temps à un appel / retour), le fait d’avoir des registres pouvant être chargés avec deux sources entraîne des coûts supplémentaires. Si la stack devient très volumineuse, il sera plus économique de remplacer les registres push-pull par une mémoire adressable. Même si une petite mémoire dédiée est utilisée pour cela, il est moins coûteux d’avoir 32 registres adressables et un registre de pointeurs à 5 bits avec une logique d’incrémentation / décrémentation, que 32 registres comportant chacun deux entrées. Si une application peut avoir besoin de plus de stack que ce qui serait facilement disponible sur le processeur, il est possible d’utiliser un pointeur de stack avec une logique pour stocker / extraire les données de la stack de la RAM principale.

Un pointeur de stack est un petit registre qui stocke l’adresse du haut de la stack. Il est utilisé dans le but de pointer l’adresse du haut de la stack.