Académique Documents
Professionnel Documents
Culture Documents
1
Source: Notes du cours du professeur Gilbert Arbez
Sujets de discussion
◼ Le processus du développement de logiciel
◼ Conception
◼ Codage
Échange de paramètres
Code structuré
◼ Le débogage du programme
◼ Lecture: Cady, Chapitre 3, 8 et 9, Conception
Tic-Tac-Toe
2
Le processus du développement de logiciel
◼ Définition de problème: Identifier ce qui devrait être fait
◼ Conception: conception structurée des modules et algorithmes
Un algorithme exprime les étapes détaillées (mais pas chaque instruction
machine)
Ex: Charger la variable varA avec le contenu pointé par pointeur ptr
varA ← [ptr] (pseudo-code) varA = *ptr; (lang. prog. C)
◼ varA et ptr peuvent être des registres ou emplacements de mémoire
Allons utiliser le C pour concevoir les programmes assembleurs
◼ Programmation: la conversion de la conception à un programme
◼ Test du programme
Test de module
Test du système
◼ L’entretien du programme
◼ La documentation
3
Spécification des besoins
◼ Bien comprendre le problème
◼ Besoin de savoir ce qui doit être fait
◼ Bonne communication avec le client est
essentielle
◼ Jeu Tic-Tac-Toe
◼ Règles du jeu
Matrice de 3 X 3
Chaque joueur à son tour pour placer X ou O dans la
matrice
Un joueur gagne quand trois X ou trois O sont en
ligne et adjacent (horizontal, vertical, diagonal)
Quand la matrice est pleine pas de gagnant,
4
Conception descendante (top-down)
◼ Conception en niveaux
◼ L’attention se tourne vers la solution du problème
◼ Le problème est divisé
Définitde plus petites tâches
Petites tâches peuvent encore être subdivisées
Dans de grands projets, les tâches sont partagées parmi plusieurs
membres d’une équipe
5
La conception du
Gameboy Tic-Tac-Toe
Tic-Tac-Toe
Gameboy
Debug12
6
Plus au sujet de la conception descendante
◼ Doit assurer que les niveaux soient corrects
Besoin de plusieurs passes
◼ Reporter les détails
Travail progressivement sur plus de détails aux niveaux inférieures
◼ Raffine la conception de façon successive
À mesure que les niveaux inférieurs, des changements sont apportés aux
niveaux supérieurs
◼ Concevoir des algorithmes
Porte l’attention d’abords aux algorithmes pour résoudre les problèmes,
sans se soucier des détails de la programmation
Utiliser un pseudo code ou un organigramme
Dans notre cas, nous allons utiliser un langage haut-niveau (C) comme
pseudocode pour représenter nos algorithmes des programmes
assembleurs.
7
Conception ascendante (bottom-up)
◼ Codage avant que la conception soit complétée
Ne respecte pas le report de détails
Peut rendre plus difficile la conception des niveaux supérieures
Viole le raffinement successif
Difficile d’optimiser les niveaux inférieurs basées sur les décisions faîtes
aux niveaux supérieurs
◼ Offre des avantages
L’utilisation d’outils génériques du code offre des fonctions générales
(Utilisation du Debug-12)
8
Approche pratique
◼ Difficile de suivre les idéaux de la conception
descendante
Utilise du code déjà disponible
Les contraintes imposées par les fonctions sont compensées par
le temps sauvé du développement du code
◼ Approche pratique
Faire avancer la conception le plus possible avant de coder
Utiliser le code déjà développé et tester lorsque c’est possible
◼ Développement itératif
Cycles besoins-conception-codage-testing pour développement
d’un système de façon itérative
Commencer avec les fonctions critiques
Développement évolutionnaire
9
Outils de conception
◼ Programmation structurée
L’utilisationde structures de base: séquence,
décision et répétition
◼ Minimise l’interaction et l’interconnexion entres éléments d’un
programme
Éviter les GOTO’s (ceci est très facile avec la
programmation assembleur)
Garder les segments de programmes petits – plus
facile à gérer
Organisation hiérarchique de la solution au problème
Une entrée et une sortie
10
Séquence d’instructions
◼ Programme C:
byte qu; // quotient de la division
byte rem; // restant de la division
qu = num/10;
rem = num%10;
*addr = qu + ASCII_CONV_NUM;
*(addr+1) = rem + ASCII_CONV_NUM;
13
If-ElseIf
sum = *ptr;
sum = sum + *(ptr+ofst2);
sum = sum + *(ptr+2*ofst2);
if(sum == (byte)XWINSUM)
retval = 'X‘
else if(sum == OWINSUM)
retval = 'O';
else
retval = SPACE;
14
While-Do
int count=9; // compteur
byte *ptr = (byte *) gamePlay;
while(count != 0)
{
*ptr++ = SPACE; // stocker espace
count--;
}
15
Do-While
int count=9; // compteur
byte *ptr = (byte *) gamePlay;
do
{
*ptr++ = SPACE; // stocker espace
count--;
} while(count != 0);
16
Do-While-Break
ptr = &gamePlay[0];
retval = '-';
cnt = 9;
do
{
if(*ptr++ == SPACE)
{
retval = SPACE;
break;
}
cnt--;
} while(cnt != 0);
◼ Attention – utilisez au minimum le break.
◼ Seulement pour simplifier la logique quand l’expression logique
du while ne suffit pas!!
17
Sous-programmes – fonctions C
◼ Définir les fonctions
Déclaration de la fonction
<type> nomFonction( <listes paramètres> )
{
// instructions
}
<type> peut être un type simple ou pointeur (adresse à un type
simple, tableau ou structure).
<listes paramètres>: déclarations de variables pour recevoir
arguments (valeurs)
Ex: int strlen(char *chaine) { … }
En assembleur, il serait possible de retourner plusieurs valeurs,
donc le C nous limite
◼ Utilisez seulement un point de sortie: une seule
instruction return à la fin de la fonction
◼ Appel de fonction
Ex: nbr = strlen(“Une chaine”);
18
Exemples
◼ Module GameBoy Tic-Tac-Toe
Programme principal
◼ Module Game Display
Sous-programme showbrd
19
L’Utilisation de modules
◼ Conception descendante mène à des programmes qui peuvent
être écrits en modules
Un membre d’équipe peut être responsable du développement d’un
module (Exemple – le module “Clavier” du lab 2).
Objectif – tenter de créer des modules indépendants
Trois attributs: fonction, liens avec les autres modules, sa logique.
20
Attributs de module
◼ Fonction:
Décrit ce que fait le module.
Certain contient une collection de fonctions sans relations, par
exemple un module utilitaire
D’autres offres des fonctions avec une relation logique, par
exemple, le module “Games Display Module”
Encore d’autre offre une simple fonction, par exemple les
modules “Test Win Module” et “Play Module””
◼ Liens entre modules
Modules interagissent entre eux
Défi: le plus possible garder les modules indépendants
Par exemple, utiliser des variables locales au lieu de globales
◼ La logique du module
Comment le module complète sa tâche
21
Échange de paramètres
◼ Les données sont
échangées entre un
sous-programme et le
code appelant
Données sont envoyées
vers le sous-
programme
Données sont
retournées par le sous-
programme
◼ Plusieurs approches
sont utilisées dans
l’échange de données
22
Techniques pour l’échange de
paramètres
◼ Avec les registres
Rapide et efficace
Général (n’affecte pas la mémoire)
Exemple: printf utilise le registre D
Mais seulement quelques registres
disponibles
◼ Les bits de code d’états
Bits de code d’état (par exemple le bit report)
peut être utilisé pour retourner une valeur
Booléenne
23
Techniques pour l’échange de
paramètres
Mémoire globale
Accessible par toutes parties du programme
Difficile de trouver le code qui cause un bogue
Accroît les liens entre modules
L’échange d’adresses de variables commun
Exemple: le “game matrix array”
◼ L’utilisation de la pile
Puissant et général
La pile sert aussi pour les variables locales
Attention aux opérations balancées
Utilisez une bonne documentation
24
L’utilisation de la pile avec les sous-
programmes ◼ Contenu de la pile
Arguments pour le sous-
SP programme (peut aussi
retourner les valeurs)
Local Variables Adresse de retour (placé
sur la pile par BSR/JSR)
Contenu de registres
Preserved sauvés (pour préserver
registers valeurs)
Espace pour variables
Return address locales
Subroutine Lorsque le RTS est
exécuté, le SP doit
arguments pointer à l’adresse de
retour
25
Traduction des invocations de fonction C
◼ Une invocation de fonction C demande l’échange des
données suivantes:
0 ou plusieurs arguments (valeurs, maximum 16 bits)
Une valeur de retour (maximum 16 bits)
Arguments et valeur de retour se limite au suivant: type simple (8
bits ou 16 bits), pointeur (à un tableau ou structure)
◼ Arguments sont placés sur la pile et dans le registre D
Un seul argument – dans le registre D
Deux ou plusieurs arguments –
◼ Empile les arguments sur la pile à partir de l’argument à la droite
dans liste d’arguments
◼ Argument la plus à gauche est placé dans le registre D
◼ Valeur de retour se place dans le registre D.
◼ Variables locales de fonctions sont placées soit sur la
pile, soit dans un registre
26
Normes pour le codage assembleur
◼ Style pour la création du code source
Adopter un format pour le code
◼ Éléments du programme
En-tête du programme
EQU d’assembleurs (définition de constantes)
Programme principal
◼ Emplacement
◼ Initialisation
◼ Code principale
◼ Fin de programme
Modules – collection de sous-programmes
◼ Placer dans des fichiers différents
Définitions des données constantes
Données variables
◼ Emplacement
◼ Allocation
Sections – pour appuyer la liaison de modules
27
En-tête de programme
Program Element Program Example
Program Header ; MC68HC12 Assembler Example
;
; This program is to demonstrate a
; readable programming style.
; It counts the number of characters
; in a buffer and stores the result in
; a data location. It then prints
; the number of characters using
; D-Bug12 Monitor routines.
; Source File: M6812EX1.ASM
; Author: F. M. Cady
; Created: 5/15/97
; Modifications: None
28
EQU d’assembleur
Program Element Program Example
System Equates. ; Monitor Equates
out2hex:EQU $FE16 ; Output 2 hex nibbles
putchar:EQU $FE04 ; Print a character
; I/O Ports
PORTH: EQU $24 ; Port H address
PORTJ: EQU $28 ; Port J address
Constant Equates ; Constant Equates
CR: EQU $0d ; CR code
LF: EQU $0a ; LF code
NULL: EQU $00 ; End of ASCII string
NIL: EQU 0 ; Initial data value
Memory Map ; Memory Map Equates
Equates PROG: EQU $4000 ; Locate the program
DATA: EQU $6000 ; Variable data areas
STACK: EQU $8000 ; Top of stack
29
Programme principal
◼ Emplacement
La directive ORG pour placer le code en mémoire
◼ Initialisation
La pile
Variables globales
◼ Code principal
Algorithme du premier niveau
◼ Fin de programme
Par exemple, SWI
30
Sous-programmes
; Subroutine - updateRow(ptr,rptr) – Display Module
; Parameters: ptr - pointer to game matrix array (in D)
; rptr - pointer to a row (on stack PBL_RPTR)
; Returns: nothing
; Variables: none
; Stack Usage
OFFSET 0 ; to setup offsets into stack
PBL_PR_Y DS.W 1 ; preserve Y - used as rptr
PBL_PR_X DS.W 1 ; preserve X - used as ptr
PBL_RA DS.W 1 ; return address
PBL_RPTR DS.W 1 ; rptr
31
Exemple
◼ Dessinez le cadre de la pile pour le segment du
programme, après la dernière leas -10,sp est
exécuté:
pshy
32
Solution
33
Appel par valeur (CALL-BY-VALUE)
Opération :
◼ Avant de donner le contrôle au sous-
programme (SUB), MAIN place les données
dans les registres (A, B, X, Y) ou dans la
mémoire, puis JSR SUB est exécutée.
34
* CALL-BY-VALUE: the SUM OF SQUARES PROGRAM squares all
the numbers of addresses $4080 to $40FF and puts the sum of
the squares as a 16-bit result in X.
; ----------------------- Start MAIN -----------------------
ORG $4000 ;start address
LDX #0 ;init sum S = 0
LDY #$4080 ;init. data block pointer
LOOP LDAA 0,Y ;prepare parameter to pass (by-value in A)
JSR SQUARE ;square it, i.e., B = MSB of (A).(A)
ABX ;sum=sum+B (SQUARE put result in B)
INY ;increment data block pointer
CPY #$4100 ;squared all data?
BNE LOOP ;get more if not done yet
SWI
; ------------------------ End of MAIN ---------------------
; SUBROUTINE SQUARE calculates the square of an 8-bit number
; as a rounded 8-bit normalized result
; calling registers: A = data to be squared
; return registers: B = rounded 8-bit normalized square
SQUARE TAB
MUL
ADCA #$00 ;round it to 8-bit result
TAB ;move approx squared rounded # in B
RTS
* -----------------------END OF SUBROUTINE SQUARE ----------35 35
CALL-BY-VALUE ( -> Stack)
; Adds 10 bytes (from a buffer stored in memory) passed onto
; the stack and returns the sum in the A register Demo LEAS instructions
NUM: EQU 10 ; Number of bytes to add
PROG: EQU $0800 ; Program location ; Subroutine to calculate a sum of NUM bytes on the stack.
DATA: EQU $0900 ; Input: B register contains the number to add
STACK: EQU $0a00 ; Top of the stack ; Output: A register contains the sum
ORG PROG ; Registers Modified: A, B and CCR
lds #STACK CalcSum:
; Push NUM bytes on the stack from an arbitrary buffer ; When the subroutine is entered, the SP is pointing
ldab #NUM ; Initialize counter in B ; to the return address. Use it to get address of data into X.
ldx #BUF ; Initialize X pointer leax 2,SP ; SP+2 -> X
; DO get the data ; Now get the data and add it all up
LoadLoop: ldaa 0,x ldaa 1,X+ ; Get first byte
; and put it on the stack decb ; Adjust the counter
psha add_loop:
inx ; Increment the pointer ; DO add the byte the SP is pointing to, and then
; WHILE the counter is not equal to zero ; increment the SP to point to the next byte
dbne b,LoadLoop adda 1,X+
; Calculate the sum ; WHILE the counter is not equal to zero
ldab #NUM dbne b,add_loop
jsr CalcSum ; A register has the sum, restore the SP to pointing
; After returning from the subroutine, you can check ; to the return address.
; the carry bit for an overflow and you can rts ; Return to the program
; restore the stack pointer ; Set up the data buffer area and put some data in it
leas NUM,SP ORG DATA
36 36
swi BUF: DC.B 1,2,3,4,5,6,7,8,9,10
Appel par référence (call-by-reference)
Pointeur de mémoire
◼ Passer le sous-programme d'une valeur de
registre contenant l'adresse des paramètres
en mémoire.
◼ Plus complexe, une charge supplémentaire
pour l'utilisation du pointeur.
37
CALL-BY-REFERENCE (-> register)
;X sum of B*B
RES EQU $407E ; GLOBAL VARIABLE RES
;MAIN ORG $4000 ;start address
LDX #0 ;init sum S = 0
LDY #$4080 ;init. data block pointer & prepare parameter to pass
;(by-reference - register Y, i.e., ptr to operand is in Y)
LOOP JSR SQUARE ;square it B = b*b
LDAB RES
ABX ;sum=sum+B
INY ;increment data block pointer
CPY #$4100 ;squared all data?
BNE LOOP ;get more if not
SWI
* SUBROUTINE SQUARE calculates the square of an 8-bit number as a rounded 8-bit #
* calling registers: Y = pointer to data to be squared
* return registers: B = rounded 8-bit normalized square
SQUARE LDAB 0,Y ; B <- m(Y)
TBA ;
MUL
ADCA #$00 ;round it to 8-bit result
STAA RES ;put result at RES (by-value - GLOBAL VARIABLE RES)
RTS
* End of program code Y 4080
* DATA MAIN SQUARE
ORG $4080
RES: M(407F) X2 38 38
Données constantes
◼ Emplacement
Utilisez la directive ORG
Normalement placé à la fin du code (destiné
pour le ROM)
Définir la section de données constantes avec
la directive SECTION (voir Module 3)
◼ Allocation
Utilisez la directive assembleur DC
39
Données Variables
◼ Emplacement
Utilisez la directive ORG pour placer les variables en RAM
Définir la section de données variables avec la directive
SECTION (voir Module 3)
◼ Allocation
Utilisez les directives d’assembleurs DC et DS
Initialiser avec le code les variables
40
Autres principes de codage
◼ Indentation ou non
Typiquement, le code assembleur n’utilise pas l’indentation
◼ Lettres majuscules et minuscules
Certains assembleurs ne sont pas sensibles à la case
Rendre les étiquettes plus faciles à lire
Tout en majuscule pour les constantes
◼ Utilisez des symboles et non des chiffres magiques
Permet d’avoir un code qui se documente
◼ Les fichiers “include”
Avec la directive “include”, il est possible d’insérer d’autres fichiers
Par exemple, définir des constantes communes et l’inclure dans un
nombre de fichiers assembleur
Définition de modules réutilisables
◼ Utilisez les sous-programmes des moniteurs
◼ Style de commentaires
Commentaire sur chaque ligne
Commentaire pour un bloc de code
Inclure dans les commentaires, le pseudo-code
41
Programmation structurée
◼ IF-ELSE
testwin
◼ IF-ELSEIF
checkLine
◼ DO-WHILE and WHILE-DO
clrbrd, showbrd, prtbrdln
◼ Using Breaks
testWin, isdraw
◼ Voir Cady Section 8.2 pour d’autres exemples
42
Expressions complexes de test
◼ do { … } while( (var1<10) && (var2>3));
do:
… ;{…}
ldaa var1 ; while( (var1 < 10)
cmpa #10
bhs endwhile
ldaa var2 ; && (var2 > 3)
cmpa #3
bhi do
endwhile: ; );
43
Expressions complexes de test
◼ if( (var1=3) || (var1=2) ) {…} else {…}
48
Déboguage d’éléments de données
◼ Que doit on examiner durant l’exécution du
programme:
Registres: Contenu des registres, y comprit de CCR
Mémoire:
◼ Les débogueurs haut niveau permettent d’examiner les
variables déclarées
◼ Avec les débogueurs de bas niveau, doit examiner la
mémoire en format hexadécimal
◼ Doit suivre le code source
Le code source est nécessaire pour suivre la logique
du programme
Le fichier « *.LST » qui montre le code machine est
très utile
◼ Peut souvent montré des erreurs en l’examinant
◼ Permet de savoir ou établir les points d’arrêt
49
Bugs typiques
◼ Mauvais transfert aux sous-programmes
◼ Oublier d’initialiser le pointeur de pile
◼ Pas assez de mémoire dans la pile
◼ Opérations de pile non balancées
◼ Sous-programmes qui détruisent des registres
◼ Registres transposés
◼ Oublier d’initialiser les registres index
◼ Oublier d’initialiser des registres ou données
◼ Modifier les codes d’états avant les instructions de
branchements
◼ Utilisez la mauvaise instruction de branchement
◼ Utilisez le mauvais mode d’adressage
◼ L’utilisation d’un compteur de 16-bit en mémoire
◼ Ne pas arrêter le programme correctement 50
Quelques trucs
◼ Utiliser l’adressage de registre lorsque possible
Plus rapide et utilise moins de mémoire
◼ Utiliser l’adressage indexé ou indirect de registre
Le prochain mode d’adressage le plus efficace
Calcule les adresse durant l’exécution
◼ La pile pour stockage temporaire
Dans les sous-programmes, attentions aux opérations balancées
◼ N’utiliser pas des numéros codés dans les instructions (magic #)
Utilisez des étiquettes qui représentent des constantes
◼ Ne faîtes pas d’initialisation des données avec l’assembleur
L’initialisation se fait seulement lors du téléchargement (ou dans un
ROM)
◼ Utilisé les fonctions de l’assembleurs
Utiliser des étiquettes, des expressions, et des macros
◼ Utiliser mais n’abuser pas des commentaires
MOV B,C ; Transfert de C à B ---- Pas significatif
MOV B,C ; Réinitialiser le compteur
51