wiki:Seance2

M1 SESI – Architecture des Processeurs et Optimisation

TME1 – VHDL – Environnement de simulation

L'objectif de ce TME est de vous familiariser avec :

  • La syntaxe de l'assembleur
  • L'écriture de programme et les conventions utilisées par le compilateur
  • L'obtention d'un exécutable à partir de fichiers assembleur
  • L'environnement de simulation
  • Le langage de description de composants matériels

En principe, les 3 premiers points ont été acquis en L3.

Le but de ce TME est de montrer comment on peut obtenir un fichier exécutable à partir d'un programme écrit en assembleur et comment on peut l'exécuter sur une plateforme matérielle.

Tous les fichiers nécessaires se trouvent sous /users/enseig/pirouz/M1/Archi/Enonce/S2_TME. Ces fichiers doivent être copiés dans un répertoire du compte de l'étudiant en respectant l'organisation en sous-répertoires.

Vous pouvez aussi récupérer les fichiers à travers l'archive suivante attachment:S2_TME.tar.gz et la décompresser avec la commande :

tar -xvzf S2_TME.tar.gz

Note : la partie sur le langage VHDL est facultative suivant les groupes.

Le langage de description de matériel VHDL.

Les exercices de ce TME sont construits autour d'un langage de description de matériel appelé VHDL (Very High Speed Integrated Circuits Hardware Description Language). Attention, il ne s'agit pas d'un langage de programmation. Ce langage permet de décrire le fonctionnement d'un circuit numérique. C'est un langage déclaratif.

La description d'un circuit comporte deux parties : une vue externe et une vue interne.

La vue externe définit ce que l'on peut voir à l'extérieur du circuit : le nom du circuit et son interface. L'interface d'un circuit est un ensemble de ports qui permettent de relier le circuit à d'autres circuits. Un port peut être composé d'un seul bit ou d'un vecteur de bits. Un port peut être en entrée (c'est-à-dire sa valeur est lue par le circuit) ou en sortie (c'est-à-dire sa valeur est écrite par le circuit) ou en entrée-sortie (si sa valeur est à la fois écrite et lue par le circuit).

La vue interne définit le fonctionnement du circuit : comment la valeur des sorties est calculée à partir des entrées.

On distingue deux types de vues internes. Lorsque le circuit est relativement complexe, on peut le décrire comme une interconnexion de composants plus simples. Il s'agit d'une description structurelle. Dans une description structurelle, on utilise donc des composants et des signaux. Un signal peut être composé d'un bit ou d'un vecteur de bits. Les signaux servent à relier des instances de composants. Une instance est un exemplaire d'un certain composant. Par exemple une carte bi-processeur contient deux instances du même composant (processeur).

Lorsque le circuit est relativement simple, on peut décrire directement l'expression (booléenne) des sorties. Il s'agit d'une description comportementale. Une description comportementale utilise donc des signaux. Un signal peut être composé d'un bit ou d'un vecteur de bits. Le comportement de chaque signal est définit par une expression booléenne ou par un vecteur d'expressions booléennes. Les expressions booléennes utilisent les opérateurs booléens : and, or, xor, nand, nor et not. On dispose également de l'opérateur de comparaison =.

En VHDL, on ne distingue pas les caractères minuscules des majuscules (toto, ToTo et TOTO désignent la même chose).

Exemple :

Voici la description comportementale d'un circuit simple qui calcule la parité de 4 signaux. Il a une seule sortie. La sortie vaut 1 si les 4 entrées présentent un nombre impair de 1.

entity PARITE is        -- vue externe
  port (
       signal a : in  bit ;     -- a : 1 bit en entree
       signal b : in  bit ;     -- b : 1 bit en entree
       signal c : in  bit ;     -- c : 1 bit en entree
       signal d : in  bit ;     -- d : 1 bit en entree
       signal p : out bit       -- p : 1 bit en sortie
       ) ;
end ;
architecture COMPORTEMENTALE of PARITE is       -- vue interne
       signal x : bit ; -- x : signal interne
       signal y : bit ; -- y : signal interne
begin
       x <= a xor b ;
       y <= c xor d ;
       p <= x xor y ;
end ;

Attention : le symbole <= est une assignation. Un signal ne peut être assigné qu'une seule fois. x <= a xor b ; indique que x est le ou-exclusif de a et de b. Dès que la valeur de a ou de b change, la valeur de x est mise à jour. C'est une différence fondamentale entre un langage de description de matériel et un langage de programmation. Un langage de description de matériel est un langage parallèle. La description suivante est strictement équivalente à la précédente :

architecture COMPORTEMENTALE of PARITE is       -- vue interne
       signal x : bit ; -- x : signal interne
       signal y : bit ; -- y : signal interne
begin
       p <= x xor y ;
       y <= c xor d ;
       x <= a xor b ;
end ;

Voici d'autres vues internes pour le même circuit.

architecture COMPORTEMENTALE of PARITE is       -- vue interne
       signal x : bit ; -- x : signal interne
       signal y : bit ; -- y : signal interne
begin
       p <= x xor y ;
       y <= '0' when ((c xor d) = '0') else     -- assignation conditionnelle
            '1' ;

       x <= a xor b ;
end ;
architecture COMPORTEMENTALE of PARITE is       -- vue interne
       signal x : bit ; -- x : signal interne
       signal y : bit ; -- y : signal interne
begin
       p <= x xor y ;
       y <= '0' when (c = '0' and d = '0') else
            '0' when (c = '1' and d = '1') else
            '1' ;

       x <= a xor b ;
end ;
architecture COMPORTEMENTALE of PARITE is       -- vue interne
       signal x : bit ; -- x : signal interne
       signal y : bit ; -- y : signal interne
begin
       p <= x xor y ;

       with c & d select        -- concatenation
         y <= '0' when B"00" ,  -- assignation selective
              '0' when B"11" ,
              '1' when others;

       x <= a xor b ;
end ;
architecture COMPORTEMENTALE of PARITE is       -- vue interne
  begin
       p <= a xor b xor c xor d ;
end ;

Voici la description du même circuit avec un vecteur de bits en entrée.

entity PARITE_VECT is   -- vue externe
  port (
       signal a : in  bit_vector (3 downto 0);
       signal p : out bit       
       ) ;
end ;

architecture COMPORTEMENTALE of PARITE_VECT is  
  begin
       p <= a(0) xor a(1) xor a(2) xor a(3) ;
end ;

L'environnement de simulation

Une description VHDL ne peut pas être exécutée directement. Elle ne représente que la manière dont un circuit fonctionne. Pour pouvoir exécuter une description VHDL il faut donc indiquer quelles sont les valeurs que l'on souhaite appliquer aux entrées du circuit. L'exécution du circuit – on parle plutôt de simulation du circuit – consiste à propager les valeurs appliquées aux entrées à travers le circuit pour calculer la valeur des tous les signaux. C'est le rôle du simulateur.

Les valeurs appliquées aux entrées du circuit sont décrites dans un fichier particulier qu'on appelle le fichier de stimuli ou de patterns. Ce fichier décrit les valeurs successives à appliquer aux entrées et les sorties que l'on souhaite observer.

Le simulateur prend en entrée le fichier qui décrit le circuit et le fichier qui décrit les patterns et produit le résultat de la simulation dans un fichier au même format que le fichier de pattern.

Exemple :

Voici la description d'un fichier de patterns en entrée pour le circuit Parite.

in  a ;       -- a : 1 bit en entree
in  b ;       -- b : 1 bit en entree
in  c ;       -- c : 1 bit en entree
in  d ;;      -- d : 1 bit en entrée
out p -trace; -- p : 1 bit a observer

begin
  : 0000 ; -- on applique 0000
  : 0001 ; -- puis 0001
  : 1101 ; -- puis 1101
  : 1100 ; -- etc
end ;

Voici la description d'un fichier de patterns résultat de la simulation Parite.

in     a ;  -- a : 1 bit en entree
in     b ;  -- b : 1 bit en entree
in     c ;  -- c : 1 bit en entree
in     d ;; -- d : 1 bit en entrée
out    p ;  -- p : 1 bit a observer

begin
  : 0000 ?0;  -- 0000 resultat -> 0
  : 0001 ?1;  -- 0001 resultat -> 1
  : 1101 ?1;  -- 1101 resultat -> 1
  : 1100 ?0;  -- etc
end ;

On peut aussi demander à observer un signal interne.

signal parite.x -trace;	-- x a observer

Voici la description d'un fichier de patterns en entrée pour le circuit Parite_Vect.

in  a (3 downto 0) X ;; -- a format hexa
out p -trace;           -- p a observer

begin
  : 0 ; -- on applique 0000
  : 1 ; -- puis 0001
  : d ; -- puis 1101
  : c ; -- etc
end ;

Et le résultat de la simulation Parite_Vect.

in  a (3 downto 0) X ;; -- a format hexa
out p ;  -- p a observer

begin
  : 0 ?0;       -- 0000 resultat -> 0
  : 1 ?1;       -- 0001 resultat -> 1
  : d ?1;       -- 1101 resultat -> 1
  : c ?0;       -- etc
end ;

Une description VHDL comportementale doit être écrite dans un fichier qui porte le même nom que le circuit (en minuscule) avec l'extension .vbe.

Une description VHDL structurelle doit être écrite dans un fichier qui porte le même nom que le circuit (en minuscule) avec l'extension .vst.

Une description des patterns doit être écrite dans un fichier avec l'extension .pat.

Pour lancer la simulation d'un circuit on utilise la commande suivante s'il s'agit d'un circuit décrit de manière comportementale. Les noms des fichiers sont donnés au simulateur sans l'extension.

simulad –b –bdd –p 50 –l 1 –nostrict <fichier_VHDL> <fichier_Patterns> <fichier_Resultat>

Pour lancer la simulation d'un circuit on utilise la commande suivante s'il s'agit d'un circuit décrit de manière structurelle. Les noms des fichiers sont donnés au simulateur sans l'extension.

simulad –bdd –p 50 –l 1 –nostrict <fichier_VHDL> <fichier_Patterns> <fichier_Resultat>

Pour accéder aux fichiers le simulateur a besoin de savoir pour chaque composant quel est le type de description utilisé (structurelle ou comportementale). Cette information est donnée dans le fichier CATAL. Ce fichier liste le nom des composants décrits de manière comportementale.

Exemple :

parite		C
parite_vect	C

Enfin le simulateur a besoin de connaître les répertoires où il peut trouver les descriptions. Cette information est donnée à travers des variables d'environnement.

Exemple :

setenv MBK_IN_LO          vst
setenv MBK_CATA_LIB  .:../cpu

Exercice 1 :

Ecrire la description comportementale d'un additionneur 32 bits et la simuler. L'additionneur reçoit en entrée deux vecteurs de 32 bits opa et opb et génère en sortie un vecteur 32 bits sum .

On rappelle que pour chaque bit de l'additionneur, il faut calculer la somme et la retenue sortante. La retenue sortante est utilisée comme retenue entrante par le bit suivant. La somme est le ou-exclusif des deux opérandes et de la retenue entrante. La retenue sortante vaut 1 si les deux opérandes et la retenue entrante présentent au moins deux 1.

Ecriture d'un programme en assembleur

A priori, il suffit de connaître le jeu d'instructions du Mips et les règles d'utilisation des registres pour pouvoir écrire des programmes en assembleur.

Toutefois, le langage assembleur du Mips est peu plus riche que le jeu d'instructions. Le langage assembleur contient un certain nombre de macro-instructions pour faciliter l'écriture des programmes. Une macro-instruction est une suite d'instructions (du jeu d'instructions du processseur).

Les macro-instructions :

Dans le jeu d'instruction du Mips, il n'y a pas d'instruction Nop (No Operation). Il s'agit d'une instruction dont l'exécution de modifie pas l'état de la machine. Par contre, le langage assembleur reconnaît la macro-instruction Nop et la traduit par Sll r0, r0, 0.

Les autres macro-instructions sont :

Move   rx, ry          traduit par   Addu  rx, ry, r0
Beqz   rx, label       traduit par   Beq   rx, r0, label	
Bnez   rx, label       traduit par   Bne   rx, r0, label	
La     rx, label       traduit par   Lui   rx, label_poids_fort
                                     Ori   rx, rx, label_poids_faible
Li     rx, imd_32bits  traduit par   Lui   rx, imd_32bits_poids_fort
                                     Ori   rx, rx, imd_32bits_poids_faible

De plus, le langage assembleur reconnaît un certain nombre de directives qui permettent d'initialiser le contenu de la mémoire et de contrôler les adresses où les données et le code sont placés.

Directives de réservation de mémoire :

Ces directives permettent de réserver de la mémoire et éventuellement de l'initialiser.

.word imd_1_32bits, ... permet de réserver des mots (4 octets) et de les initialiser. Les données sont placées à des adresses consécutives

.half imd_1_16bits, ... permet de réserver des demi-mots (2 octets) et de les initialiser. Les données sont placées à des adresses consécutives

.byte imd_1_8bits, ... permet de réserver des octets et de les initialiser. Les données sont placées à des adresses consécutives

.skip nbr_octets permet de réserver nbr_octets octets

.space nbr_octets permet de réserver nbr_octets octets

.asciiz "string" permet de réserver et d'initialiser un chaîne de caractères. La chaîne string est complétée avec le caractère de fin de chaîne ('\0')

.ascii "string" permet de réserver et d'initialiser une chaîne de caractères. La chaîne string n'est pas complétée avec le caractère de fin de chaîne ('\0')

Directives de placement mémoire :

Cette directive permet d'indiquer l'emplacement mémoire où doivent être placés les objets (codes ou données) qui suivent.

Exemple :

.text place les objets qui suivent dans la section .text

En fait, la directive désigne une section d'entrée où placer l'objet.

Un fichier de paramètres associe à chaque section d'entrée une section de sortie et définit l'emplacement mémoire des sections de sortie. Ce fichier de paramètres est le fichier ldscript.

Le fichier ldscript contient la description des sections de sortie et leur emplacement en mémoire. De plus, ce fichier permet de définir des symboles et leur attribuer une valeur. Ces symboles peuvent être utilisés dans les fichiers assembleur.

Un fichier ldscript peut être relativement complexe. Ici, nous utilisons une version simplifiée de ce fichier.

Exemple :

/* ###--------------------------------------------------------------### */
/* file           : ldscript                                            */
/* date           : Apr 29 2009                                         */
/* description    : ldscript for mips assemply programs                 */
/* ###--------------------------------------------------------------### */

        /* ###------------------------------------------------------### */
        /*   sections                                                   */
        /* ###------------------------------------------------------### */

SECTIONS
  {
        /* ###------------------------------------------------------### */
        /*   addresses as symbols :                                     */
        /*                                                              */
        /*     - user           text  address                           */
        /*     - user           stack address                           */
        /*     - user global    data  address                           */
        /*     - user controllers     address                           */
        /*                                                              */
        /*     - kernel global  data  address                           */
        /*                                                              */
        /*     - exception      text  address                           */
        /*     - boot           text  address                           */
        /*     - boot exception text  address                           */
        /* ###------------------------------------------------------### */

   user_text_begin    = 0x00400000                          ;
   user_stack_begin   = 0x7fffe000                          ;
   user_data_begin    = 0x10000000                          ;

   kernel_stack_begin = 0xffffe000                          ;
   kernel_data_begin  = 0xc0000000                          ;
   kernel_term_begin  = 0xc0001000                          ;

   excp_text_base     = 0x80000000                          ;
   boot_excp_base     = 0xbfc00100                          ;

   excp_base_offset   = 0x00000080                          ;

   excp_text_begin    = excp_text_base   + excp_base_offset ;
   boot_excp_begin    = boot_excp_base   + excp_base_offset ;
   boot_text_begin    = 0xbfc00000                          ;

        /* ###------------------------------------------------------### */
        /*   section descriptions                                       */
        /* ###------------------------------------------------------### */

  .text               user_text_begin    : { *(.text           ) }
  .stack              user_stack_begin   : { *(.stack          ) }
  .data               user_data_begin    : { *(.data   .rodata ) }

  .reset              boot_text_begin    : { *(.boot   .reset  ) }
  .bexcep             boot_excp_begin    : { *(        .bexcep ) }

  .ktext              excp_text_begin    : { *(.ktext  .excep  ) }
  .kstack             kernel_stack_begin : { *(.kstack         ) }
  .kdata              kernel_data_begin  : { *(.kdata  .krodata) }
  }

La valeur des symboles peut être, soit une constante, soit calculée par une expression. La description des sections de sortie comporte le nom de la section, son adresse et la liste des sections d'entrée qui la compose. On peut voir dans l'exemple ci-dessus que la section de sortie .data se trouve à l'adresse 0x10000000 et qu'elle est composée des sections d'entrée .data et .rodata.

L'assemblage des programmes

L'outil assembleur permet de générer une image mémoire à partir de fichiers écrits en assembleur. Cet outil prend en entrée une liste de fichiers assembleur et le fichier ldscript et génère une image mémoire dans un fichier de sortie.

asm -set reorder -ld <ldscript> -mips32 -o <fichier_image> <fichier_ass> ...

Exercice 2 :

Le programme main suivant (fichier strcpy.u) affiche une chaîne de caractères src puis la copie dans une chaîne trg. Ensuite, il affiche la chaîne trg et quitte le programme. L'affichage d'une chaîne de caractères se fait en appelant la fonction puts. La fonction strcpy permet de copier une chaîne de caractères. Enfin, la fonction exit permet de quitter le programme main.

Compléter ce fichier en écrivant la fonction strcpy (les autres fonctions sont fournies dans d'autres fichiers assembleur -- le fichier std_32.u contient les fonctions puts et exit, le fichier std_32.x le programme de traitement des exceptions et std_32.r le programme de reset).

Assembler votre programme avec la commande suivante et vérifier l'image mémoire obtenue (fichier strcpy.mem)

asm -set reorder -ld mips32_ld -mips32 -o strcpy.mem strcpy.u std.u std.x std.r

En ajoutant l'option –s strcpy.sym à la commande on obtient la liste des symboles utilisés dans le programme.

Cette commande peut être invoquée par le script ASM_32.csh :

./ASM_32.csh strcpy
;  ### -------------------------------------------------------------- ###
;  # file   : strcpy.u                                                  #
;  # date   : Sep  8 2009                                               #
;  # descr. : functional test for Mips R3000                            #
;  ### -------------------------------------------------------------- ###
        ;  ### ------------------------------------------------------ ###
        ;  #   data section                                             #
        ;  ### ------------------------------------------------------ ###
                        .data
source_str :            .asciiz "Have a nice day"
target_str :            .space  128
        ;  ### ------------------------------------------------------ ###
        ;  #   text section                                             #
        ;  ### ------------------------------------------------------ ###
                        .text
        ;  ### ------------------------------------------------------ ###
        ;  #   make the label _main visible for other files             #
        ;  ### ------------------------------------------------------ ###
                        .globl  _main
        ;  ### ------------------------------------------------------ ###
        ;  #   main                                                     #
        ;  ### ------------------------------------------------------ ###
_main :
                        la              r16, source_str
                        la              r17, target_str
        ;  ### ------------------------------------------------------ ###
        ;  #   print the source string                                  #
        ;  ### ------------------------------------------------------ ###
                        add     r4 , r0 , r16
                        jal     _puts
        ;  ### ------------------------------------------------------ ###
        ;  #   call strcpy                                              #
        ;  ### ------------------------------------------------------ ###
                        add     r4 , r0 , r17
                        add     r5 , r0 , r16
                        jal     _strcpy
        ;  ### ------------------------------------------------------ ###
        ;  #   print the target string                                  #
        ;  ### ------------------------------------------------------ ###
                        add     r4 , r0 , r17
                        jal     _puts
        ;  ### ------------------------------------------------------ ###
        ;  #   exit                                                     #
        ;  ### ------------------------------------------------------ ###
                        addi    r4 , r0 , 0         ; exit value
                        jal     _exit
        ;  ### ------------------------------------------------------ ###
        ;  #   strcpy                                                   #
        ;  ### ------------------------------------------------------ ###
_strcpy :
                        ...
                        .end

La plateforme de simulation pour le processeur MIPS

Une plateforme de simulation construite autour d'un processeur Mips permet de simuler l'exécution d'un programme assembleur. Outre le processeur Mips, cette plateforme comporte des bancs mémoires pour les instructions et les données, un terminal d'affichage et un décodeur d'adresses. Le décodeur d'adresses sélectionne, en fonction de l'adresse émise par le processeur, le banc mémoire qui doit répondre au processeur.

Plateforme de simulation

Sur cette plateforme les bancs mémoires sont initialisés à partir de l'image mémoire obtenue par l'assemblage d'un programme assembleur. Cette image doit se trouver dans le fichier ram.ini et ce fichier doit être placé dans le répertoire où la simulation est lancée.

Le fichier de patterns nécessaire à la simulation est très simple. En pratique, cette plateforme n'a que deux entrées : l'horloge et le signal de reset. Pendant le premier cycle de simulation, le signal reset est actif (ce signal est actif à l'état bas) puis, il reste inactif pendant le reste de la simulation. L'horloge est signal périodique qui passe successivement de 0 à 1 et de 1 à 0.

Exercice 3 :

Simuler l'exécution du programme main (fichier strcpy.u) sur la plateforme. Pour cela il suffit d'exécuter le script SIM.csh : ./SIM.csh ../asm/strcpy

Exercice 4 :

Le programme main suivant (fichier strlen.u) affiche une chaîne de caractères src puis, calcule la longueur de cette chaîne en appelant la fonction strlen. Ensuite, le résultat de fonction strlen est transformé en une chaîne de caractères par la fonction uitoa_d. Enfin, la fonction main affiche cette chaîne et sort en appelant la fonction exit.

Compléter ce fichier en écrivant la fonction strlen (les autres fonctions sont fournies dans d'autres fichiers assembleur). Vous pouvez essayer plusieurs versions de strlen et vérifier la différence du nombre de cycles nécessaires à la simulation.

Assembler votre programme avec la commande ./ASM.csh strlen

;  ### -------------------------------------------------------------- ###
;  # file   : strlen.u                                                  #
;  # date   : Sep  8 2009                                               #
;  # descr. : functional test for Mips R3000                            #
;  ### -------------------------------------------------------------- ###
        ;  ### ------------------------------------------------------ ###
        ;  #   data section                                             #
        ;  ### ------------------------------------------------------ ###
                        .data
source_str :            .asciiz "Have a nice day"
head_str   :            .ascii  "longeur de la chaine : "
tail_str   :            .space  128
        ;  ### ------------------------------------------------------ ###
        ;  #   text section                                             #
        ;  ### ------------------------------------------------------ ###
                        .text
        ;  ### ------------------------------------------------------ ###
        ;  #   make the label _main visible for other files             #
        ;  ### ------------------------------------------------------ ###
                        .globl  _main
        ;  ### ------------------------------------------------------ ###
        ;  #   main                                                     #
        ;  ### ------------------------------------------------------ ###
_main :
                        la              r16, source_str
                        la              r17, head_str
                        la              r18, tail_str
        ;  ### ------------------------------------------------------ ###
        ;  #   print the source string                                  #
        ;  ### ------------------------------------------------------ ###
                        add     r4 , r0 , r16
                        jal     _puts
        ;  ### ------------------------------------------------------ ###
        ;  #   call strlen                                              #
        ;  ### ------------------------------------------------------ ###
                        add     r4 , r0 , r16
                        jal     _strlen
        ;  ### ------------------------------------------------------ ###
        ;  #   convert the length into a string                         #
        ;  ### ------------------------------------------------------ ###
                        add     r4 , r0 , r2
                        add     r5 , r0 , r18
                        jal     _uitoa_d
        ;  ### ------------------------------------------------------ ###
        ;  #   print the result                                         #
        ;  ### ------------------------------------------------------ ###
                        add     r4 , r0 , r17
                        jal     _puts
        ;  ### ------------------------------------------------------ ###
        ;  #   exit                                                     #
        ;  ### ------------------------------------------------------ ###
                        addi    r4 , r0 , 0             ; exit value
                        jal     _exit
        ;  ### ------------------------------------------------------ ###
        ;  #   strlen                                                   #
        ;  ### ------------------------------------------------------ ###
_strlen :
                        ...
                        .end

Exercice 5 :

Ouvrez le fichier strupper.u du répertoire asm. Écrivez la fonction strupper. Testez votre solution et vérifiez qu'elle est correcte sur plusieurs chaînes de caractères (plus ou moins de majuscules, d'autres types de caractères que des lettres). Vous pourrez tester différentes versions assembleur de la même fonction et comparer le temps nécessaire à l'exécution de chacune.

Exercice 6 :

Ouvrez le fichier strcmp.u qui se trouve dans le répertoire asm. Programmez une version simplifiée de la fonction strcmp qui étant données deux chaines de caractères str1 et str2 rend 0 si les deux chaînes sont égales, rend -1 si str1 est inférieure à str2 et rend 1 sinon.

Dans le main vous afficherez le résultat en utilisant des chaînes de caractères globales. Vous afficherez 'chaines identiques', ou 'première chaine inferieure' ou 'premiere chaine superieure' dans le main en fonction du résultat de votre fonction appelée sur deux chaînes déclarées comme globales. Testez votre solution en testant tous les cas possibles.

Pouvez vous réduire le temps d'exécution de la fonction en changeant le code de votre fonction ?

Exercice 7 :

En vous inspirant des fichiers précédents et du TD précédent, écrivez un programme principal qui affiche un tableau d'entiers, le tri et l'affiche une fois trié. On suppose que le tableau est une variable globale et que sa taille aussi.

Last modified 8 years ago Last modified on Sep 21, 2016, 11:29:11 AM

Attachments (2)

Download all attachments as: .zip