Guide explicatif sur le chapitre 9 des notes de cours de
GABRINI, Ph. -- Organisation des ordinateurs et assembleur.

chapitre 9. Les sous-programmes.

Exemples de sous-programmes utilisés par ce guide:  SOUS-PROGRAMMES

Lire la page 107 et porter attention à la Figure 9.1 (Ordre d’exécution des instructions).


9.1 Instructions CALL et RETn

Lire cette section concernant les instructions CALL et RETn (page 108).

Sous PEP8, exécuter avec le débogueur le programme SOUSPROG.

Il faut porter attention à  la section memory trace (en bas à gauche dans PEP8).
Le pointeur de pile (Stack Pointer) se trouve au départ à l'adresse FBCD (sommet de la pile).
Après chaque CALL, le sommet de pile (SP) est décrémentée de 2 octets afin d'y conserver l'adresse de retour.
FBCD -> FBCB

Après chaque RET0, l'adresse de retour qui se trouve au sommet de la pile (SP) est récupérée et copiée dans le compteur ordinal
puis le sommet de pile(SP) est augmenté de 2 octets.
FBCB -> FBCD

Cet espace libéré de 2 octets n'a pas à être initialisé à zéro car de toute façon il sera écrasé au prochain CALL.

Examinons l'exemple de la page 109 (programme SAPIN).

Sous PEP8, exécuter avec le débogueur le programme SAPIN.
 

9.2 Paramètres

9.2.1 Paramètres valeurs.

On passe les paramètres au sous-programme par les registres A  et X.

Sous PEP8, exécuter avec le débogueur le programme MULT-1.

testons avec 4 et 3.

; IN:     A=multiplicande

;           X=multiplicateur

; OUT: A=produit

;           X=0

On constate que le sous-programme MULTIP a besoin d'une variable locale "mucande" de 2 octets.

mucande: .EQUATE 0 ; #2d

qui doit être alloué  avec SUBSP 2,i ; empilons le multiplicande #mucande

exemple supplémentaire: Sous PEP8, exécuter avec le débogueur le programme SOUS1.

Ce programme appelle un sous-programme qui retourne la plus grande
valeur parmi 2 nombres dont les valeurs proviennent des registres A et X.

Le retour au programme principal se fera avec RET2 qui est l'équivalent de ADDSP 2,i suivi de RET0
ce qui permettra de relâcher les 2 octets de la variable locale "mucande".

9.2.2 Paramètres variables

Il faut trouver une méthode générale qui fonctionnera quelque soit le nombre de paramètres.
On ne conserve plus les paramètres dans les registres A et X.

9.3 Adressage sur la pile

9.3.1 Adressage direct sur la pile (S)

Page 111.

La figure 9.2 (Instruction avec adressage direct sur la pile) indique que la recherche sur la pile est un déplacement par rapport au sommet de pile(SP)).

Dans cet exemple, on veut copier dans la variable VARIA, la valeur qui se trouve 6 octets plus bas que le sommet de pile(SP).

On pourrait simplement faire LDA 6,s
car varia: .EQUATE 6

Sous PEP8, exécuter avec le débogueur le programme BULLETIN de la page 112.

au lieu de déclarer dans le programme:

totalEx:  .BLOCK 2
final:      .BLOCK 2
miSess:  .BLOCK 2
bonus:    .BLOCK 2

 

On réserve l'espace nécessaire (8 octets) sur la pile:

SUBSP 8,i ; allouer espace variables locales

A la fin du sous-programme,

on libère l'espace réservé avec

ADDSP 8,i ; libérer espace pile

Prenons l'exemple suivamt:

; Programme qui appelle un sous-programme qui retourne la plus grande

; valeur parmi 2 nombres lus dont les valeurs sont inscrites sur la pile.

en passant les paramètres sur la pile.

Sous PEP8, exécuter avec le débogueur le programme SOUS2.

;IN:     SP+0=valeurB

;          SP+2=valeurA

;

;OUT: SP+0=la valeur la plus grande est retournée

le programme principal copie sur la pile les 2 valeurs à comparer:
DECI    nombre,d ; première valeur
LDA     nombre,d
STA     -2,s ;
DECI    nombre,d ; deuxième valeur
LDA     nombre,d
STA     -4,s ;
SUBSP 4,i ; #valeurA #valeurB

nous retrouvons dans le sous-programme:

sauveA:  .EQUATE 0 ; #2h

retour:     .EQUATE 2 ; #2h

valeurB:  .EQUATE 4 ; #2h

valeurA:  .EQUATE 6 ; #2h

;

SOUS2:  SUBSP 2,i ; #sauveA

Au début du sous-programme SOUS2,
comme celui-ci modifiera le registre A,
il faut en prendre une copie afin de le remettre tel quel à la fin du sous-programme.

Une fois, le traitement effectué, nous remettons le registre A dans son état original

et ne conservons que la valeur la plus grande:

LDA retour,s

STA valeurB,s ; on ne conserve sur la pile que la valeur la plus grande

LDA sauveA,s  ; registre A original

RET4          ; désempilons #sauveA #retour (équivalent à ADDSP 4,i suivi de RET0)

Un autre exemple:

Sous PEP8, exécuter avec le débogueur le programme MULT-2.

; Programme qui appelle un sous-programme avec passage de
; paramètres sur la pile.
; Il effectue la multiplication d'un
; multiplicande par un multiplicateur.
;
; Les nombres positifs et négatifs sont acceptés.

testons avec 4 et 3.

; IN: SP+0=multiplicateur
;       SP+2=multiplicande
;       SP+4=produit (à venir)
;       SP+6=code de retour (à venir)
; OUT: SP+0=produit
;           SP+2=code retour (0 si parfait; -1 si débordement rencontré)

le programme principal ajoute sur la pile le multiplicateur et le multiplicande.
de plus, il faut prévoir 2 octets pour le produit
et 2 octets pour un code de retour indiquant si la multiplication a bien réussi (car il peut y avoir un débordement lors du calcul)
pour un total de 8 octets.

SUBSP 8,i ; ajustement du sommet de pile #coderet #produit #mucande #mucateur

Au début du sous-programme MULTIP,
comme celui-ci modifiera les registres A et X,
il faut en prendre une copie au départ afin de les remettre tels quels à la fin du sous-programme.
De plus, une variable SIGNE sera nécessaire pour le traitement des nombres négatifs.

MULTIP: SUBSP 6,i ; pour sauver les registres A et X ainsi que la variable signe #sauveX #sauveA #signe

Une fois, le traitement effectué, nous remettons les registres A et X originaux

et ne conservons que le produit et le code de retour (0=succès,-1=échec)

       LDA   sauveA,s

       LDX   sauveX,s

       ADDSP 10,i       ; désempilons #signe #sauveA #sauveX #mulret #mucateur

       RET0

 

L'instruction RET10 n'existe pas. Seules les instructions RET0 à RET7 sont disponibles.

 

Au retour du sous-programme de multiplication,
le programme principal s'assurera d'abord du bon fonctionnement de cette multiplication.

        LDX  2,s ; analysons le code de retour qui doit être 0 (-1=débordement)
        BREQ parfait
erreur: STRO msgdéb,d
        BR arrêt
;
parfait:DECO 0,s  ; affichons le produit
arrêt:  ADDSP 4,i ; désempilons #produit #coderet

9.3.2 Adressage indexé sur la pile (SX)

Page 112.

Comme l'illustre la figure 9.3 (Calcul de l'adresse effective de l'opérande indexé sur la pile) à la page 113,
vecteur est un tableau de 6 éléments qui occupent 12 octets.

Vecteur: .EQUATE 4
LDX 8,i
LDA Vecteur,sx ; prendre Vecteur[X]

Nous retrouvons dans la pile:

2 octets                     ; <- Sommet de la pile (SP)
2 octets
2 octets Vecteur[5]    ; 4 octets par rapport au sommet de pile(SP)
2 octets Vecteur[4]
2 octets Vecteur[3]
2 octets Vecteur[2]
2 octets Vecteur[1]    ; 8 octets passés le début de Vecteur
2 octets Vecteur[0]

LDA Vecteur,sx ; indique de prendre Vecteur + contenu de X, soit Vecteur+8 octets, soit SP+4+8 octets (SP+12)

Sous PEP8, exécuter avec le débogueur le programme VECTEUR de la page 113.

Celui-ci nécessite la conservation d'un index (2 octets) et d'un tableau (12*2 octets)

SUBSP 26,i ;espace pour l'index (2 octets) et le tableau (24 octets)

Remarque: l'index augmente de 0 à 11 tandis que la position dans le tableau augmente de 0 à 22,
0,2,4,6,8,10,12,14,16,18,20,22
car chaque élément du tableau occupe 2 octets.

vecteur(0) = position 0 dans le tableau
vecteur(1) = position 2 dans le tableau
vecteur(2) = position 4 dans le tableau
...
vecteur(11) = position 22 dans le tableau

Un autre exemple:

Sous PEP8, exécuter avec le débogueur le programme SOUS3.

; Programme qui appelle un sous-programme qui retourne la plus grande

; valeur d'un tableau de 5 nombres dont les valeurs sont copiées sur la pile.(SX)

 

Les 5 nombres lus sont conservés dans un tableau pouvant être visualisés avec le débogueur:

nombres: .BLOCK 10 ; #2d5a

 

Au retour du sous-programme, on retrouvera sur la pile le plus grand nombre.

DECO  0,s  ; affichage du nombre maximum

ADDSP 2,i  ; on l'enlève de la pile #tableaux

9.3.3 Adressage indirect sur la pile (SF)

Page 114.

La figure 9.4 (Adressage indirect sur la pile) indique

AdVal : .EQUATE 6
 
STA AdVal,sf

Le champ "Adr. opérande" contient une adresse de référence (pointeur).

Sous PEP8, exécuter avec le débogueur le programme SOUS4.

; Programme qui appelle un sous-programme qui affiche une chaîne de caractères

; dont l'adresse est inscrite sur la pile.(SF)

9.3.4 Adressage indirect indexé sur la pile (SXF)

Page 115.

Le champ "Adresse V" contient une adresse de référence (pointeur) sur un tableau V.

Si on veut récupérer V[4]:

AdVect: .EQUATE 6    ; position dans la pile de Adresse V
LDX 8,i              ; V[4] 
STA AdVect,sxf       ; récupération de V[4]

fait ranger le contenu du registre A dans l’opérande V[8] (les éléments du vecteur V sont repérés par
des indices aux octets). Dans un premier temps, l’adresse calculée est SP + AdVect; ceci conduit à
l’adresse du vecteur sur la pile. De là, on atteint le vecteur, que l’on indice alors par le registre d’index.

Conclusion: SXF se fait en 3 étapes:
1-S: récupère l'adresse de SP + Advect: SP+6 octets: "Adresse V"
2-X: ajout de X octets à cette adresse récupérée: "Adresse V"+8 octets (contenu de X)
3-F: récupération de la valeur pointée à l'Adresse V + 8 octets, soit "Opérande"

Sous PEP8, exécuter avec le débogueur le programme SXF-1.

; Ce programme fait appel à une routine qui affiche le Xième

; caractère de l'alphabet.

; Ce caractère sera choisi par l'utilisateur.

Sous PEP8, exécuter avec le débogueur le programme SXF-2.

; Ce programme fait appel à une fonction qui retourne

; au programme principal le Xième caractère de l'alphabet.

; Ce caractère sera choisi par l'utilisateur.

Sous PEP8, exécuter avec le débogueur le programme SOUS5.

; Programme qui appelle un sous-programme qui retourne la sommation

; des valeurs d'un tableau dont le nombre d'éléments et l'adresse

; sont fournis sur la pile.(SXF)

 

9.4 Réalisation du passage de paramètres

9.4.1 Passage d’un paramètre valeur

page 116.

Sous PEP8, exécuter avec le débogueur le programme HISTO de la page 116.

; Programme permettant d'afficher un histogramme des valeurs lues
 

9.4.2 Passage de plusieurs paramètres au moyen d’une seule adresse

Sous PEP8, exécuter avec le programme "Passage de plusieurs paramètres au moyen d’une seule adresseprog942 de la page 117.

Nous prendrons l’exemple suivant où les instructions d'appel empilent une seule adresse comme
paramètre d’appel (tout en réservant un espace sur la pile pour le résultat de la fonction Facture)
         LDA     typ1,i      ;Liste des cinq mots des types de service
         STA     liste1,d    ; premier paramètre
         LDA     temps,i     ;Durée
         STA     liste2,d    ; deuxième paramètre
         LDA     result,i    ;Résultat
         STA     liste3,d    ; troisième paramètre
         LDA     liste1,i    ; adresse liste de 3 pointeurs
         STA     -4,s        ; empilée après espace pour code résultat
         SUBSP   4,i         ; ajuster pointeur pile
         CALL    Facture     ;
;.......
typ1:    .WORD   3           
typ2:    .WORD   4           
typ3:    .WORD   5           
typ4:    .WORD   2           
typ5:    .WORD   0           
temps:   .WORD   10          
result:  .WORD   0           
liste1:  .BLOCK  2           ;Liste des trois pointeurs
liste2:  .BLOCK  2           
liste3:  .BLOCK  2           
                  
La Figure 9.7 (Structure des paramètres de l’appel à Facture)
illustre les pointeurs.

LDX 0,i       ; index = 0;
LDA liste,sxf ; adresse table
STA table,s   ; conservée
ADDX 2,i      ; index = 1;
LDA liste,sxf ; adresse durée
STA duree,s   ; conservée
ADDX 2,i      ; index = 2;
LDA liste,sxf ; adresse résultat
STA res,s     ; conservée
LDA duree,sf  ; valeur durée
STA duree,s   ; conservée

Le programme Facture du chapitre 10 utilise le passage de plusieurs paramètres au moyen d'une seule adresse.
Nous l'analyserons en détail au prochain chapitre.

9.4.3 Passage de paramètres par la pile

Page 119.

Cela a été expliqué précédemment dans la section 9.3.1 "Adressage direct sur la pile (S)".

Sous PEP8, exécuter avec le débogueur le programme MULT-2.

 

9.4.4 Passage de paramètres qui se trouvent déjà sur la pile.

Sous PEP8, exécuter avec le programme "Passage de paramètres qui se trouvent déjà sur la pile" prog944 de la page 120.

L’instruction MOVSPA place la valeur du pointeur de pile SP dans le registre A.

Ainsi si un sous-programme désire passer ses propres paramètres qui se trouvent sur la pile à un autre sous-programme,
il doit utiliser l'instruction MOVSPA pour les retrouver.

9.5 Conventions d’utilisation des registres.

Pour éviter les ennuis causés par le partage involontaire des registres, on utilise un certain nombre de
conventions concernant l'utilisation des registres.

9.5.1 Appels des sous-programmes et passage des paramètres

Lire la page 121.

9.5.2 Sauvegarde des registres

Lire la page 122.

9.5.3 Zone locale des sous-programmes


Figure 9.10 (Aspect du sommet de la pile après appel et sauvegarde).

Lire les pages 122 et 123.

Figure 9.11 (Cadre de pile avec espace local).

Exemple d'un cadre de pile au début d'un sous-programme:

variabl3:.EQUATE 0  ; variable locale no 3
variabl2:.EQUATE 2  ; variable locale no 2
variabl1:.EQUATE 4  ; variable locale no 1
sauveX:  .EQUATE 6  ; sauvegarde registre X
sauveA:  .EQUATE 8  ; sauvegarde registre A
adRetour:.EQUATE 10 ; adresse de retour
op2:     .EQUATE 12 ; opérande 2
op1:     .EQUATE 14 ; opérande 1
resu:    .EQUATE 16 ; résultat
 

9.6 Partage des responsabilités

9.6.1 Programme appelant

Page 124.

° s'il s'agit d'une fonction, réserver l’espace pour le résultat sur la pile
° définir les paramètres, et placer leurs adresses ou leurs valeurs sur la pile
° effectuer le branchement au sous-programme par un CALL au sous-programme
° récupérer le résultat de la fonction, si c’est le cas, et l’enlever de la pile

9.6.2 Sous-programme

Page 125.

° établir l’espace local et les paramètres en définissant un cadre de pile
° sauvegarder les registres sur la pile
° traiter le problème donné
° restaurer les contenus antérieurs des registres à partir de la pile
° nettoyer la pile (en enlevant les paramètres empilés)
° retourner au programme appelant par un RETn

Les trois premières instructions du sous-programme (avec des opérandes appropriés) effectuent le
nécessaire au début du sous-programme et constituent le prologue du sous-programme, par exemple
:

sauveX:    .EQUATE 0  ; sauvegarde X
sauveA:    .EQUATE 2  ; sauvegarde A
AdRetour:  .EQUATE 4  ; adresse retour
op2:       .EQUATE 6  ; opérande 2
op1:       .EQUATE 8  ; opérande 1
resu:      .EQUATE 10 ; résultat
;
Multipli:  SUBSP 4,i    ; espace local sauvegarde
           STA sauveA,s ; sauvegarde A
           STX sauveX,s ; sauvegarde X

En fin de sous-programme, on retrouvera
les instructions ci-dessous qui constituent l'épilogue du sous-programme:

        LDA adRetour,s  ; adresse retour
        STA op1,s       ; déplacée
        LDA sauveA,s    ; restaure A
        LDX sauveX,s    ; restaure X
        ADDSP 8,i       ; nettoyer pile
        RET0

9.6.3 Exemple de sous-programmes

Jetez un coup d'oeil aux programmes des pages 126 et des suivantes.

9.9 Sous-programme d’allocation de mémoire new

Page 130.

Le sous-programme new alloue la taille demandée (en octets) et place l'adresse
de la zone dans le pointeur dont l'adresse est passée en paramètre.
En résumé, il est possible d'obtenir dynamiquement sur demande de l'espace mémoire.
Cet espace appelé HEAP ("tas" en français) se trouve à la toute fin du programme
juste avant l'énoncé .END
heappnt:.ADDRSS HEAP ; initialement pointe à HEAP
HEAP:   .BLOCK 0
        .END

L'espace est alloué au fur et à mesure des demandes d'espace
et le pointeur "heappnt" gère l'espace disponible dans le "tas".
Il est possible de limiter la grosseur du "tas".
exemple: limite de 5000 octets:
heappnt: .ADDRSS heap   ; initialement pointe à heap
heap:    .BLOCK 5000    ; espace heap
heaplmt: .BYTE 0        ; limite supérieure
         .END


Sous PEP8, exécuter avec le débogueur le programme LISTE.

Ce programme alloue dynamiquement 5 maillons en créant une liste chainée.
Il lit au terminal 5 valeurs qui seront insérés dans chacun des maillons
et, par la suite, affichent ces 5 valeurs en ordre inverse.

Un autre exemple:

Sous PEP8, exécuter avec le débogueur le programme LISTE2.

Ce programme alloue dynamiquement "des" maillons en créant une liste chainée.
Il lit au terminal des valeurs qui seront insérés dans chacun des maillons
et, par la suite, affiche ces valeurs de la plus grande à la plus petite.