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).
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.
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".
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.
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)
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
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
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)
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)
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
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.
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.
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.

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

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
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