User Tools

Site Tools


archi:index

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
archi:index [2016/03/01 14:31] orelarchi:index [2024/03/18 15:06] (current) – external edit 127.0.0.1
Line 1: Line 1:
 ====== Architecture des Ordinateurs ====== ====== Architecture des Ordinateurs ======
  
 +  * __Supports__ : http://dept-info.labri.fr/ENSEIGNEMENT/archi/
 +  * __UE__ : 4TIN304U (6ECTS)
  
-__Supports__ : http://dept-info.labri.fr/ENSEIGNEMENT/archi/ +====Quelques Notes de TD====
- +
- +
-__ Emploi du Temps__ : [[ http://www.disvu.u-bordeaux1.fr/et/edt_etudiants2/SemCombi/Licence/Semestre2/g109220.html | Groupe A3]]+
  
   * [[archi:y86 | Assembleur y86]]   * [[archi:y86 | Assembleur y86]]
-  * [[archi:circuit Circuit]] +  * [[archi:x86 Un peu de x86]] 
-  * (...) +  * [[archi:circuit | Circuits Combinatoires Séquentiels]] 
- +  [[archi:proc | Processeur Complet]]
-===== Assembleur y86 ===== +
- +
-y86 est un langage assembleur simplifié basé sur l'architecture des processeurs x86 (IA-32). Les mots mémoires sont alignés sur 32 bits et utilise la convention //little endian//.  +
- +
-Le y86 utilise 8 registres généraux de 32 bits, dont certains ont des rôles historiques. +
-  * %eax le registre d'accummulation  +
-  * %ecx : le registre de compteur utilisé dans les boucles +
-  * %edx : un registre auxiliaire +
-  * %ebx : le registre //base index// utilisé comme pointeur sur la base d'un tableau +
-  * %esp : le registre //stack pointer// qui pointe sur le sommet du cadre d'appel de la fonction courante, c'est-à-dire le sommet de la pile +
-  * %ebp : le registre //frame base pointer// qui pointe la base du cadre d'appel de la fonction courante +
-  * %esi : le registre //source index// utilisé lors des copies de suite d'octets +
-  * %edi : le registre //destination index// utilisé lors des copies de suite d'octets +
- +
-En outre, le registre %eip (//instruction pointer//) pointe sur l'adresse de la prochaîne instruction à exécuter. Ce registre est modifié automatiquement à chaque exécution et peut être manipulé par des instruction du type jmp, call, ret. +
- +
-==== If then ==== +
- +
-Pour effectuer un branchement conditionnel qui dépend d'un test entre deux registres %eax et %ebx, on commence typiquement à comparer ces deux registres par soustraction, ce qui a pour effet de modifier les //codes de condition// (Z pour zéro, O pour overflow et S pour strictement négatif). Il suffit alors d'effectuer le branchement approprié //jle, jl, je, jne, jge, jg// (l = lower, g = greater, e = equal). +
- +
-<code c> +
-long a = 2, b = 3, c; +
-if (a < b) c = 1; +
-</code> +
- +
-<code - ifthen.ys> +
-        .pos 0 +
- mrmovl a,%eax +
- mrmovl b,%ebx +
- subl %ebx,%eax        # on calcule a-b (dans ce sens) +
- jge endif # on teste la condition de sortie : a-b >= 0 ? +
-then: irmovl 1,%ecx +
- rmmovl %ecx,c # c = 1 +
-endif: halt +
- +
-        .pos 0x100 +
-a:      .long 2 +
-b:      .long 3 +
-c:      .long 0   +
-</code> +
- +
-__Astuce__ : L'instruction //subl// modifie la registre cible, ce qui présente un inconvénient. Dans le cas où l'on souhaite tester si un registre %eax est égal à zéro (ou non) avec //je// (ou //jne//), une astuce consiste à effectuer l'opération //andl %eax,%eax// ;-) +
- +
-==== If then Else ==== +
- +
-<code c> +
-long a = 2, b = 3, c; +
-if (b <= a) c = 1; else c = 2; +
-</code> +
- +
-<code - ifthenelse.ys> +
-        .pos 0 +
- mrmovl a,%eax +
- mrmovl b,%ebx +
- subl %eax,%ebx        # on calcule b-a (dans ce sens) +
- jg else         # on teste la condition du else : b-a > 0 ? +
-then: irmovl 1,%ecx +
- rmmovl %ecx,c # c = 1 +
-        jmp endif +
-else:   irmovl 2,%ecx +
-        rmmovl %ecx,c # c = 2 +
-endif: halt +
- +
-        .pos 0x100 +
-a:      .long 2 +
-b:      .long 3 +
-c:      .long 0   +
-</code> +
- +
- +
-==== Boucle For ==== +
- +
-<code c> +
-long sum = 0; +
-for(i = 1 ; i <= 10 ; i++) sum += i; +
-</code> +
- +
-<code - sum.ys> +
- .pos 0 +
- mrmovl sum,%edx # %edx: sum +
- irmovl 1,%eax # %eax: i = 1 +
- +
-loop:   rrmovl %eax,%ebx +
- isubl 10,%ebx # on calcule i-10 +
- jg end                  # condition arrêt si i-10 > 0 +
- addl %eax,%edx # sum += i +
- iaddl 1,%eax # i++ +
- jmp loop  +
-end: rmmovl %edx,sum +
- halt +
- +
- .pos 0x100 +
-sum: .long 0 +
-</code> +
- +
- +
-__Note Bene__ : On peut un peu simplifier ce code en parcourant la boucle à l'envers... la comparaison à zéro est toujours plus facile à écrire ;-) +
- +
-==== Pointeurs ==== +
- +
- +
-<code c> +
-long a = 1, b = 0; +
-long * p = &a; +
-b = *p;              /* b = 1 */ +
-*p = 2;              /* a = 2 */ +
-</code> +
- +
-Dans le code suivant, on utilisera le registre %esi pour désigner le pointeur p. +
- +
-<code> +
-        irmovl a,%esi           # p = &a +
-        mrmovl (%esi),%eax      # b = *p +
-        rmmovl %eax,           +
- irmovl 2,%eax # *p = 2 +
-        rmmovl %eax,(%esi) +
- +
-        .pos 0x100 +
-a:      .long 1  +
-b:      .long 0 +
-</code> +
- +
-==== Les tableaux ==== +
- +
-On rappelle que l'étiquette //t// représente une //adresse immédiate//. La notation //(%ebx)// désigne //l'adresse indirecte// en mémoire pointée par le registre //%ebx//. La notation //4(%ebx)// correspond à l'adresse //(%ebx)+4//. Notons qu'un //long// compte pour 4 octets. +
- +
-<code> +
- irmovl t,%ebx           # l'adresse t est mis dans %ebx, qui joue le rôle de pointeur +
-        mrmovl (%ebx),%eax      # load: %eax = t[0] +
-        ... +
-        rmmovl %ecx,(%ebx)      # t[0<- %ecx +
-        rmmovl %ecx,4(%ebx)     # t[1] <- %ecx        +
- +
- .pos 0x100 +
-t: .long 1                 # tableau t d'adresse 0x100 et de taille 4 long +
- .long 2 +
- .long 3 +
- .long 4 +
-</code> +
- +
-//expliquer la variante d'adressage indexé : t(%eax)// +
- +
-==== Décalage des valeurs dans un tableau ==== +
- +
-<code c> +
-for(i = 0 ; i < n-1; i++)  +
-  t[i] = t[i+1]; +
-</code> +
- +
-<code - decalage.ys> +
- .pos 0 +
- +
- mrmovl n,%ecx +
- irmovl t,%ebx  +
-  +
-loop: isubl 1,%ecx # n-- +
- je end +
- mrmovl 4(%ebx),%eax # t[0<- t[1] +
- rmmovl %eax,(%ebx)  +
- iaddl 4,%ebx # t += 4  +
- jmp loop +
- +
-end: halt +
- +
- .pos 0x100 +
-n: .long 5 +
-t: .long 1 +
- .long 2 +
- .long 3 +
- .long 4 +
- .long 5 +
-</code>  +
- +
- +
-==== Appel de fonction et Pile ==== +
- +
-<code c> +
-long f(long i, long j) { return (i+j); } +
-long a = f(1,2); +
-</code> +
- +
- +
-<code - function.ys> +
-        .pos 0 +
- irmovl stack,%esp       # initialisation du pointeur de pile (stack pointer) +
-        jmp main +
- +
-f:      mrmovl 4(%esp),%eax     # on récupère le premier paramètre (a) +
-        mrmovl 8(%esp),%ecx     # on récupère le second paramètre (b) +
-        addl %ecx,%eax          # variable de retour dans %eax +
-        ret +
- +
-main:   mrmovl b,%eax           # on empile les paramètres en sens inverse +
-        pushl %eax +
-        mrmovl a,%eax +
-        pushl %eax +
-        call f                  # appel de la fonction f() +
-aret:   popl %ecx               # on dépile les 2 paramètres avec popl +
-        popl %ecx               # ou iaddl 8,%esp +
-        rmmovl %eax,res   +
-        halt          +
- +
-        .pos 0x100 +
-a:      .long 1 +
-b:      .long 2 +
-res:    .long 0 +
- +
- .pos 0x200              # adresse de base de la pile +
-stack:                          +
- +
-</code> +
- +
- +
-Tout d'abord, il faut noter que la pile stocke les données dans l'ordre décroissant des adresses mémoire, à partir de l'adresse //stack// (0x200) vers la zone des variables (0x100) ! Le registre //%esp// est le pointeur de pile (ou //stack pointer//) qui désigne le sommet de la pile à l'adresse //(%esp)//+
- +
- +
-Avant l'appel de fonction //f()//, on commençe par empiler ces paramètres avec //pushl// dans l'ordre inverse ! Au moment de l'appel de fonction avec l'instruction //call//, l'adresse de retour de la fonction (notée //aret//) est automatiquement empilée et se trouve donc au sommet de la pile. Le retour de fonction avec l'instruction //ret// dépile automatiquement cette adresse et fait sauter le programme sur //aret//. Il faut encore dépiler les paramètres avec //popl// ou en ajoutant explicitement à //%esp// la taille nécessaire (2 long ici, soit 8 octets). +
- +
-Par convention, on place la valeur de retour de la fonction dans le registre //%eax//. +
- +
-__Nota Bene__ : Il ne faut pas oublier d'initialiser la pile au départ du programme ! A la fin du programme, on peut vérifier que %esp est revenu à sa valeur initiale //stack//+
- +
-==== Sauvegarde des registres lors d'un appel de fonction ===== +
- +
-Lors d'un appel de fonction, certains registres utilisés par l'appelant peuvent être modifié par l'appelé ! Il convient donc de les sauvegarder sur la pile. En principe, on distingue deux types de registres : +
-  * les registres //caller-saved// (%eax, %ecx, %edx) qui doivent être sauvegardés par l'appellant si nécessaire ; +
-  * les registres //callee-saved// (%ebx, %esi, %edi, %ebp), qui doivent être sauvegardés par l'appelé. +
- +
-<code - > +
- +
- +
-main:   # sauvegarde des registres caller +
-        pushl %eax               +
-        pushl %ecx               +
-        pushl %edx                       +
-        # empilement des paramètres de f +
-        ... +
-        call f +
-        # dépilement des paramètres de f +
-        ... +
-        # restauration des registres caller +
-        popl %edx                +
-        popl %ecx +
-        popl %eax +
-        halt                 +
- +
-f:      # récupération des paramètres +
-        ... +
-        # sauvegarde des registres callee +
-        pushl %ebp               +
-        pushl %esi +
-        pushl %edi +
-        pushl %ebx +
-        ... +
-        ... +
-        ... +
-        # restauration des registres callee +
-        popl %ebx                +
-        popl %edi +
-        popl %esi         +
-        popl %ebp         +
-        ret +
- +
-</code> +
- +
-__Nota Bene__ : En pratique, on sauvegardera uniquement les registres utiles pour éviter d'allourdir le code. Attention à la modification de %esp ! +
- +
-==== Appel de fonction avec des variables locales ==== +
- +
-Les variables locales sont définies dans la pile après l'adresse de retour. On accède donc aux variables à partir de (%esp), mais du coup les paramètres sont décalés ! Le code de la fonction précédente est modifié pour utiliser une variable locale ! +
- +
- +
-<code - funcloc.ys>  +
-        .pos 0 +
-main: irmovl stack,%esp       # initialisation du pointeur de pile (stack pointer) +
-        mrmovl b,%eax           # on empile le second param b +
-        pushl %eax +
-        mrmovl a,%eax # on empile le premier param a +
-        pushl %eax +
-        call f                  # appel de la fonction f() +
-aret:   popl %ecx               # on depile le premier param +
-        popl %ecx               # on depile le second param +
-        rmmovl %eax,res         # recup resultat +
- halt +
- +
-f:      isubl 4,%esp # alloc variable locale x sur la pile +
- mrmovl 8(%esp),%eax     # recup premier param a +
-        mrmovl 12(%esp),%ebx    # recup second param b +
-        ...                     # compute x +
- mrmovl (%esp),%ecx # load x +
-        pushl %ecx              # save x +
-        ...                     # do something else +
- mrmovl (%esp),%eax      # restore x (variable de retour dans %eax) +
- iaddl 4,%esp # liberation variable locale x +
-        ret +
-  +
-        .pos 0x100 +
-a: .long 1 +
-b: .long 1 +
-res:    .long 0         +
- +
- .pos 0x200 # adresse de base de la pile +
-stack:                          +
-</code> +
- +
-__Nota Bene__ : Dans un soucis de simplification, il est choisi ici (et plus tard) de ne pas utiliser le registre %ebp ! +
- +
- +
-====Passage par référence dans les fonctions ==== +
- +
-Dans les exemples précédent de fonction, nous avons utiliser le //passage de paramètres par valleur//+
-Ici, nous donnons l'exemple d'une fonction //swap(&a,&b)// qui utilise le //passage par référence//. Il s'agit d'échanger les valeurs de deux entiers. +
- +
- +
-<code - swap.ys> +
- .pos 0 +
-main: irmovl stack,%esp # init de la pile  +
- irmovl b,%eax  +
- pushl %eax # empiler &b +
- irmovl a,%eax +
- pushl %eax # empiler &a +
- call swap +
- iaddl 8,%esp # depiler +
- halt +
- +
-swap: mrmovl 4(%esp),%eax # param pa=&a +
- mrmovl 8(%esp),%ebx # param pb=&b +
- mrmovl (%eax),%ecx # valeur a=*pa +
- mrmovl (%ebx),%edx # valeur b=*pb +
- rmmovl %ecx,(%ebx) # swap *pb = a  +
- rmmovl %edx,(%eax) # swap *pa = b  +
- ret +
-  +
- .pos 0x100 +
-a: .long 1 +
-b: .long 2 +
- +
- .pos 0x200 +
-stack:  +
-</code> +
- +
-==== Fonction manipulant un tableau ==== +
- +
-//todo// +
- +
-==== Appel récursif de fonction ==== +
- +
-<code c> +
-f(n) { if(n == 0) return 0 ; else return (f(n-1)+n) ; } +
-main() { res = f(10); } +
-</code> +
- +
-<code - recursif.ys> +
- .pos 0 +
-main: irmovl stack,%esp +
- mrmovl n,%eax +
- pushl %eax # empiler param n +
- call f +
- iaddl 4,%esp # depiler param +
- rmmovl %eax,res # resultat dans %eax +
- halt +
- +
-f: mrmovl 4(%esp),%ecx # param n +
- andl %ecx,%ecx # eval condition code +
- je f0 # si n = 0 ? +
-fn: isubl 1,%ecx # n-1 +
- pushl %ecx # empiler param n-1 +
- call f # retour dans %eax +
- iaddl 4,%esp # depiler param +
- mrmovl 4(%esp),%ecx # restore param n  +
- addl %ecx,%eax # retour dans %eax = n + f(n-1) +
- ret +
-f0: irmovl 0,%eax  +
- ret # valeur de retour dans %eax +
-  +
- +
-end: halt +
- +
- .pos 0x100 +
-n: .long 10 +
-res: .long 0 # res = 55 = 0x37 +
- +
- +
- .pos 0x200 +
-stack:  +
-</code>  +
- +
- +
-==== Structure Liste Chaînée ==== +
- +
-<code c> +
-struct list {  +
-  long x; +
-  struct list * next; +
-}; +
- +
-long length(struct list * l) { +
-  long n = 0; +
-  while(l) { n++; l = l->next; } +
-  return n; +
-+
-</code> +
- +
-<code - linkedlist.ys> +
-main:   .pos 0 +
-        irmovl stack,%esp +
-        irmovl l1,%eax +
-        pushl %eax +
-        call length             # retour dans %eax +
-        iaddl 4,%esp +
-        halt +
- +
-length: mrmovl 4(%esp),%esi     # param l +
-        xorl %eax,%eax          # n = 0 +
-loop:   andl %esi,%esi          # test si l est NULL ? +
-        je end +
-        iaddl 1,%eax            # n++ +
-        mrmovl 4(%esi),%esi     # l = l->next +
-        jmp loop +
-end:    ret                     # retour n dans eax         +
- +
-        .pos 0x100              # linked list  +
-l1:     .long 1                  +
-        .long l2                # next = l2 +
-l2:     .long 2 +
-        .long l3                # next = l1 +
-l3:     .long 3 +
-        .long 0                 # next = NULL                 +
-        .pos 0x200 +
-stack: +
-</code> +
  
archi/index.1456842697.txt.gz · Last modified: 2024/03/18 15:05 (external edit)