Questions sur les exercices de TD et d'examen

2019

contrôle 3 du 30 avril 2019

Comment fait-on pour trouver les paramètres de la fonction f?
réponse
Manifestement la fonction f a trois arguments puisque:

2020

TD7

assembleur

Y a-t-il des sites qui traitent de l'assembleur et du langage machine décrit dans ce cours?
réponse
Non, il n'y a pas de site qui traite de l'assembleur utilisé ici, car c'est en fait une simplification importante de l'assembleur du pentium (x68). Tous les mnémoniques des instructions machines utilisés existent pour le pentium sauf: Ce paragraphe utilise la syntaxe de l'assembleur at&t et non pas intel.

binaire

Pouvez vous me définir précisément ce que vous attendez lorsque vous demandez d'écrire en langage binaire? Est-ce le langage entre le langage C et le langage assembleur ou bien est-ce remplir les 4 cases qui figurent à droite du code?
réponse
Prendre des instructions comme
add r1,r2,r14
et les transcrire en binaire par
0000 0000 0000 0001 0000 0010 0000 1110
est le travail d'un programme appelé "assembleur". L'assembleur transforme donc un programme écrit en "langage d'assemblage" ou "langage assembleur" ou "source assembleur" ou plus simplement "assembleur" en un programme écrit en binaire. Mais un nombre écrit en binaire (c'est-à-dire en base 2, avec les deux chiffres 0 et 1) est assez pénible à lire. Si on regroupe les bits (chiffres binaires) quatre par quatre, on obtient un nombre écrit en hexadécimal (en base 16) avec les 16 chiffres 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e et f. On obtient donc dans notre exemple
00 01 02 0e.
On peut aussi regrouper les bits huit par huit et le nombre écrit en base 256 est
0 1 2 14.
C'est en fait ce que je vous demande de faire quand je demande d'écrire le programme en "binaire". C'est donc un abus de langage. Je devrais en toute rigueur vous demander de l'écrire en base 256. En fait quand on lit du code binaire sur un ordinateur, on le lit bien en base 256, mais les chiffres en base 256 ne sont pas écrits en décimal de 0 à 255 mais en hexadécimal de 0 à ff. La notation la plus courante est donc plutôt
00 01 02 0e.

exercice 1

Pourquoi fait-on store R2 R3 et non pas load? Pourtant les deux sont des affectations.
réponse
Il y a d'abord x=*t ( load r1,r3) qui copie la valeur d'un élément du tableau t (situé dans la ram) dans x, qui est représenté par un registre (situé dans le cpu).
Puis il y a *u=x (store r2,r3) qui copie cette même valeur depuis ce registre du cpu, vers un élément du tableau u (qui est situé dans la ram).
Les tableaux t et u sont dans la ram à l'extérieur du cpu. Pour copier la valeur d'une case du tableau t, vers une case du tableau u, il faut donc d'abord copier cette valeur dans un registre du cpu (par un load) puis retransmettre cette même valeur dans l'autre sens du cpu vers la ram (dans une autre cellule de la ram) par un store.
La valeur de *t (dans la ram) est d'abord copiée dans x (dans le cpu) puis de là dans *u (dans la ram).
On ne peut pas copier directement de *t dans *u.

TD8

exercice 4

Je ne comprends pas comment traduire les opérations avec les + entourés qui sont des xor dans l'exercice 4 du td8.
réponse
Si on remplaçait dans la procédure le xor par un add, elle ferait la somme de tous les éléments du tableau et remplacerait les éléments du tableau par les sommes partielles.
t={1,-6, 2,4,-3,7} deviendrait
t={1,-5,-3,1,-2,5} car
1+-6=-5
-5+ 2=-3
-3+ 4= 1
1+-3=-2
-2+ 7= 5
C'est pareil en remplaçant le + par un ⊕.
t={1,-6, 2, 4,-3,7} devient
t={1,-5,-7,-3, 0,7} car
1⊕-6=-5
-5⊕ 2=-7
-7⊕ 4=-3
-3⊕-3= 0
0⊕ 7= 7
Malheureusement si je sais calculer de tête le ou exclusif des petits entiers positifs (comme 6⊕5=110⊕101=011=3), je ne sais pas le faire pour les nombres négatifs. J'utilise donc l'associativité et la commutativité du ou exclusif, et le fait que (-1)⊕a=-1-a Donc je détaille les calculs comme 1⊕-6=1⊕(5⊕-1)=(1⊕5)⊕-1=(001⊕101)⊕-1=100⊕-1=4⊕-1=-5

TD9

exercice 1

Dans l'exercice 1 du td9, je ne comprend pas quel va être l'effet dans la fonction signée, du décalage de 31 vers la droite( operation sarimm) de mon registre r0 dans le registre r2.
réponse
Pour obtenir le reste d'une division euclidienne, il faut faire une division d'un nombre de 64 bits par un nombre de 32 bits. On obtient alors un reste de 32 bits et un quotient de 32 bits. Il faut donc transformer un nombre sur 32 bits en un nombre de 64 bits. Ce nombre de 64 bit est rangé dans deux registres de 32 bits. La partie basse est le nombre sur 32 bits. La partie haute contient 32 bits nuls si le nombre est non signé ou s'il est positif (ou nul). Mais elle contient 32 fois le bit 1 si le nombre est signé et négatif. Si le nombre à étendre (de 32 à 64 bits) est dans le registre r8, et que l'on veut mettre son extension de signe dans le registre r43, on peut écrire cela en C comme
unsigned ha=0;
ou
int ha= 0>a? -1 :0;
autrement dit
int ha;
if(0>a) ha=-1;
else ha=0;
En assembleur cela donne:
xor r43,r43,r43 // ha=ha^ha
ou
sarimm r8,31,r43 // ha=a>>31
En effet quand on décale a de 31 bits vers la droite, tous les bits sauf le bit haut sont perdus. Le bit haut par contre est décalé vers la droite juqu'au bas du mot, mais il est dupliqué 31 fois à sa gauche. On obtient donc à la fin un mot formé de 32 fois le même bit 0 ou 1, égal au bit haut de a. Donc si le bit haut de a est 1 (si 0>a) alors ha est rempli de 32 bits à 1 (ha=-1). Si le bit haut de a est nul (a>=0) alors ha est rempli de 32 bits à 0 (ha=0).

exercice 1

Je ne comprend pas comment on trouve 255 255 248 dans l'exo 1 du TD9.
réponse
jmp pgcd
recule de 8 instructions par rapport à l'instruction qui suit le jmp. On aurait donc pu écrire
jmp $-8
Après un octet contenant 44, le codop du jmp, il faut mettre trois octets, c'est-à-dire 24 bits, représentant le nombre signé -8.
8=00000000 00000000 00001000
-8=11111111 11111111 11111000
Les deux premiers octets sont 11111111 = 255. Le dernier octet est 1111100=100000000-1000=256-8=248

exercice 2

J'ai du mal à comprendre la logique de l'exercice 2 du td9 et notamment l'utilisation de l'opération bsf. Je n'arrive pas bien à comprendre à quoi elle sert.
réponse
L'algorithme binaire de calcul du pgcd de 49 et 91 est:
pgcd(49,91)=pgcd(49,42)=pgcd(49,21)=pgcd(28,21)=pgcd(7,21)=pgcd(7,14)=pgcd(7,7)=7
car
91-49=42=2*21, __builtin_ctz(42)=1 et 42>>1=21
49-21=28=2*2*7, __builtin_ctz(28)=2 et 28>>2=7
21-7=14=2*7, __buitin_ctz(14)=1 et 14>>1=7
Pour transformer 28 en 7, on le divise par 2 tant qu'il est pair. Cela pourrait se faire par:
while(a%2==0) a/=2;
ou par
while((a&1)==0) a>>=1;
Mais le nombre d'itérations de cette boucle (2 pour 28) est le nombre de 0 consécutifs qui terminent l'écriture en binaire de a=28=11100. De même que la plus grande puissance de 10 qui divise 25000 est 10^3, car 25000 se termine par trois 0. C'est pareil en binaire pour les puissances de 2. Il existe en C une fonction __builtin_ctz(a) qui nous donne ce nombre de 0 qui terminent l'écriture en binaire de a. Cette fonction est facile à calculer, puisque les nombres sont déjà écrits en binaire dans l'ordinateur, il suffit de compter les zéros au bout du nombre. En fait sur la plupart des architectures d'ordinateur il existe une instruction qui le fait. Sur un pentium, par exemple, il y en a deux: L'architecture ARM est un autre exemple. Il n'y a pas d'instruction machine équivalente au tzcnt, mais on peut la réaliser en deux instructions: d'abord un rbit qui retourne les bits du mots, puis un clz qui compte les zéros en tête du mot retourné. Donc __builtin_ctz(a) calcule rapidement combien de fois la boucle
while((a&1)==0) a>>=1;
se ferait et permet de remplacer n décalages d'un bit vers la droite par un seul décalage de n bits vers la droite:
a>>=__builtin_ctz(a)
Cela remplace une boucle itérée en moyenne 2 fois, dont les branchements conditionnels de fin sont donc très souvent mal prédits et donc très lents, par deux ou trois instructions machine assez rapides. Cette façon de faire est donc plus rapide. On suppose donc que notre machine a une instruction notée bsf qui se comporte comme le tzcnt du pentium:
bsf r3,r5
met dans r5 le nombre de zéros au bout de la valeur de r3. Autrement dit bsf r3,r5 est équivalente à r5=__builtin_ctz(r3). (de même que add r2,r3,r4 est équivalente à r4=r2+r3)
Les noms bizarres de toutes ces instructions s'expliquent par: En fait
a>>=__builtin_ctz(a);
se compile par exemple en
bsf r8,r32
sar r8,r32,r8
qui se comprend comme
{ int x=__builtin_ctz(a); a>>=x; }
en supposant que la variable a est rangée dans le registre r8 et que le registre r32 est libre et peut être utilisé pour y mettre la variable temporaire x.

examen en ligne du mardi 21 avril 2020 de 12h à 14h

L'examen peut-il se faire avec un smartphone?
réponse
Oui on peut faire l'examen avec un smart phone, en utilisant par exemple google chrome pour se connecter sur le site https://examens-segmi.parisnanterre.fr/

examen en ligne du mardi 21 avril 2020 de 12h à 14h

Si je commence l'examen sur ordinateur et qu'il blue screen pourrai-je revenir sur le site ou serai-je bloqué?
réponse
Vous pourrez revenir sur le site à partir d'un autre ordinateur ou smart phone. Vous ne serez pas bloqué, du moment que vous fournissez votre numéro d'étudiant et votre mot de passe.