Lors de l'écriture du chargeur de démarrage STM8uLoader pour microcontrôleurs STM8, il est devenu nécessaire de mesurer la profondeur de la pile.
Posons des questions:
- Que se passe-t-il si vous essayez de pousser plus d'informations sur la pile que sa profondeur?
- Que se passe-t-il si vous essayez d'extraire plus d'informations de la pile que vous n'en avez placées?
- Que se passe-t-il si vous initialisez le pointeur de pile SP avec une adresse qui dépasse les limites de la pile?
La mémoire RAM et la profondeur de pile peuvent varier pour différents modèles STM8.
Pour l'étude, le modèle STM8S103F3 a été choisi.
La documentation du STM8S103F3 fournit les données suivantes:
- profondeur de pile 513 octets;
- lors de la réinitialisation, le pointeur SP est initialisé à 0x03FF (RAM END);
- la pile croît dans le sens des adresses décroissantes.
Le calcul montre que la limite inférieure de la pile est:
0x03FF - 513 = 0x01FF
Pour briser cette limite, vous devez pousser un peu plus de 513 octets sur la pile.
Le contenu de la pile ne nous intéresse pas. Il suffit de connaître le contenu du pointeur vers la pile SP, qui doit contenir l'adresse de la prochaine cellule RAM non occupée par la pile.
Nous allons placer séquentiellement les octets avec n'importe quelle commande push (par exemple, pousser A) et avant chaque étape, envoyer le contenu de l'octet SPH élevé et SPL bas du pointeur de pile SP à l'UART.
Algorithme de procédure:
1 Initialisez le pointeur de pile avec la valeur 0x03FF et configurez l'UART;
2 Nous attendons tout octet du programme terminal;
3 octets acceptés;
4 Envoyez le contenu du pointeur SP à l'UART;
5 Nous poussons le contenu de la batterie sur la pile avec la commande push A;
6 Si les cycles d'envoi sont inférieurs à 64, passez à l'étape 4;
7 Si les cycles d'envoi 64, passez à l'étape 2.
; UART 9600/8N1 mov UART1_BRR2, #$00 ; mov UART1_BRR1, #$0D ; / mov UART1_CR2, #%00001100 ; SP $03FF ldw X, #$03FF ; X <= RAM END ldw SP, X ; SP <= X ; wait_rx_byte: btjf UART1_SR, #5, wait_rx_byte ; ld A, UART1_DR ; bset PB_DDR,#5 bset PB_CR1,#5 ldw Y, #64 ; Y <= 64 stack_cycle: ldw X, SP ; X <= SP ; SPH UART ; rlwa X ; A <- XH <- XL <- A ld A, XH ; A <- XH ld UART1_DR, A ; UART1_DR <= A wait_tx_byte_XH: btjf UART1_SR, #7, wait_tx_byte_XH ; SPL UART ; rlwa X ; A <- XH <- XL <- A ld A, XL ; A <- XL ld UART1_DR, A ; UART1_DR <= A wait_tx_byte_XL: btjf UART1_SR, #7, wait_tx_byte_XL ; A push A ; M(SP
Nous observons comment le programme terminal accepte séquentiellement le contenu du pointeur SP à partir de 0x03FF:
03 FF 03 FE 03 FD 03 FC 03 FB 03 FA 03 F9 03 F8 03 F7 03 F6 03 F5 03 F4 03 F3 03 F2 03 F1 03 F0 03 EF 03 EE 03 ED 03 EC 03 EB 03 EA 03 E9 03 E8 03 E7 03 E6 03 E5 03 E4 03 E3 03 E2 03 E1 03 E0 03 DF 03 DE 03 DD 03 DC 03 DB 03 DA 03 D9 03 D8
Une fois que la valeur atteint 0x01FF (bordure de pile précédemment calculée)
le pointeur SP a de nouveau pris la valeur 0x03FF (la pile fermée en anneau)
et a commencé à écraser les données les plus anciennes
02 0F 02 0E 02 0D 02 0C 02 0B 02 0A 02 09 02 08 02 07 02 06 02 05 02 04 02 03 02 02 02 01 02 00 01 FF 03 FF 03 FE 03 FD 03 FC 03 FB 03 FA 03 F9 03 F8 03 F7 03 F6 03 F5 03 F4 03 F3 03 F2 03 F1 03 F0 03 EF 03 EE 03 ED 03 EC 03 EB 03 EA 03 E9
Voyons maintenant comment se comporte le contenu du pointeur SP si nous essayons de récupérer de manière illimitée le contenu de la pile.
Algorithme de procédure:
1 Initialisez le pointeur de pile avec la valeur 0x03FF et configurez l'UART;
2 Nous attendons tout octet du programme terminal;
3 octets acceptés;
4 Nous extrayons le contenu de la pile avec la commande «pop A» vers la batterie;
5 Envoie le contenu du pointeur SP à l'UART;
6 Si les cycles d'envoi sont inférieurs à 64, passez à l'étape 3;
7 Si les cycles d'envoi 64, passez à l'étape 2.
Les éléments 4 et 5 de l'algorithme et la commande «push A» sont échangés avec la commande «pop A».
Malgré le fait que nous ayons initialisé le pointeur SP avec la valeur 0x03FF déjà après la première commande pop A, le pointeur a pris la valeur 0x01FF et a continué d'augmenter vers 0x03FF.
01 FF 02 00 02 01 02 02 02 03 02 04 02 05 02 06 02 07 02 08 02 09 02 0A 02 0B 02 0C 02 0D 02 0E 02 0F 02 10 02 11 02 12 02 13 02 14 02 15 02 16 02 17 02 18 02 19 02 1A 02 1B 02 1C 02 1D 02 1E 02 1F 02 20 02 21 02 22 02 23 02 24 02 25 02 26
Atteindre la valeur 0x03FF. après la prochaine commande pop A, le pointeur a de nouveau pris la valeur 0x01FF et a continué d'augmenter vers 0x03FF.
03 EF 03 F0 03 F1 03 F2 03 F3 03 F4 03 F5 03 F6 03 F7 03 F8 03 F9 03 FA 03 FB 03 FC 03 FD 03 FE 03 FF 01 FF 02 00 02 01 02 02 02 03 02 04 02 05 02 06 02 07 02 08 02 09 02 0A 02 0B 02 0C 02 0D 02 0E 02 0F 02 10 02 11 02 12 02 13 02 14 02 15
Dans le sens opposé, avec un nombre excessif d'instructions pop (w), la pile est également fermée dans un anneau de 513 octets.
La pile dans STM8S103F3 est linéaire jusqu'à ce que vous cassiez l'une de ses bordures 0x01FF ou 0x03FF.
Dès que vous franchissez l'une des limites, la pile devient un anneau de 513 octets.
Peu importe où dans l'anneau (aux adresses 0x01FF ... 0x03FF) il y aura un haut / bas de la pile, nous pouvons mettre un nombre illimité d'octets sur la pile, mais nous ne pouvons pas extraire plus de 513 octets non endommagés (le plus récent).
Maintenant que la pile est localisée à 0x01FF ... 0x03FF, il est temps de casser cette plage lors de l'initialisation du pointeur SP.
À l'étape 1 de la première procédure, nous remplaçons la valeur 0x03FF pour initialiser le pointeur SP par la valeur 0x01FE.
Nous observons comment la pile de l'adresse 0x01FE s'est dirigée vers des adresses décroissantes.
01 FE 01 FD 01 FC 01 FB 01 FA 01 F9 01 F8 01 F7 01 F6 01 F5 01 F4 01 F3 01 F2 01 F1 01 F0 01 EF 01 EE 01 ED 01 EC 01 EB 01 EA 01 E9 01 E8 01 E7 01 E6 01 E5 01 E4 01 E3 01 E2 01 E1 01 E0 01 DF 01 DE 01 DD 01 DC 01 DB 01 DA 01 D9 01 D8 01 D7
Ayant atteint l'adresse 0x0000, la pile a quitté la mémoire RAM et est entrée dans les cellules de mémoire FLASH inaccessibles au STM8S103F3.
00 16 00 15 00 14 00 13 00 12 00 11 00 10 00 0F 00 0E 00 0D 00 0C 00 0B 00 0A 00 09 00 08 00 07 00 06 00 05 00 04 00 03 00 02 00 01 00 00 FF FF FF FE FF FD FF FC FF FB FF FA FF F9 FF F8 FF F7 FF F6 FF F5 FF F4 FF F3 FF F2 FF F1 FF F0 FF EF
Il ne peut être question d'appels de sous-programme ou d'interruptions une fois que le pointeur a quitté la mémoire RAM. Certes, quelque part dans les profondeurs de la pile, les données les plus «anciennes» sont restées, qui ont eu la chance d'être enregistrées dans la mémoire RAM.
Essayons maintenant de récupérer les données de la pile avec l'initialisation «interdit» (hors de la plage 0x01FF ... 0x03FF) du pointeur SP.
Commençons par les adresses en dehors de la RAM. Dans l'étape 1 de la deuxième procédure, nous remplaçons la valeur 0x03FF d'initialisation du pointeur SP par la valeur 0xFFF8.
Nous observons comment la pile est entrée dans la mémoire RAM.
FF E9 FF EA FF EB FF EC FF ED FF EE FF EF FF F0 FF F1 FF F2 FF F3 FF F4 FF F5 FF F6 FF F7 FF F8 FF F9 FF FA FF FB FF FC FF FD FF FE FF FF 00 00 00 01 00 02 00 03 00 04 00 05 00 06 00 07 00 08 00 09 00 0A 00 0B 00 0C 00 0D 00 0E 00 0F 00 10
Traversant la frontière inférieure 0x01FF, la pile est entrée sur son territoire.
01 E9 01 EA 01 EB 01 EC 01 ED 01 EE 01 EF 01 F0 01 F1 01 F2 01 F3 01 F4 01 F5 01 F6 01 F7 01 F8 01 F9 01 FA 01 FB 01 FC 01 FD 01 FE 01 FF 02 00 02 01 02 02 02 03 02 04 02 05 02 06 02 07 02 08 02 09 02 0A 02 0B 02 0C 02 0D 02 0E 02 0F 02 10
Ayant atteint l'adresse 0x03FF, la pile s'est fermée en anneau.
03 E9 03 EA 03 EB 03 EC 03 ED 03 EE 03 EF 03 F0 03 F1 03 F2 03 F3 03 F4 03 F5 03 F6 03 F7 03 F8 03 F9 03 FA 03 FB 03 FC 03 FD 03 FE 03 FF 01 FF 02 00 02 01 02 02 02 03 02 04 02 05 02 06 02 07 02 08 02 09 02 0A 02 0B 02 0C 02 0D 02 0E 02 0F
Conclusions:
La pile dans STM8S103F3 est capable d'exécuter ses tâches uniquement dans la plage 0x01FF ... 0x03FF.
Pour obtenir la plus grande profondeur linéaire, le pointeur de pile SP dans STM8S103F3 doit être initialisé à 0x03FF.
La pile dans STM8S103F3 est linéaire jusqu'à ce que vous cassiez la borne inférieure 0x01FF.
Dès que vous franchissez la limite inférieure, la pile devient un anneau de 513 octets.