Examen final IFT209 Programmation système
Examen final IFT209 Programmation système
Examen final
Enseignant: Michael Blondin
Date: jeudi 27 avril 2023
Durée: 3 heures
Directives:
— Répondez aux questions dans le cahier de réponses, pas sur ce questionnaire;
— Une feuille (recto verso) de notes au format 81/2” × 11” est permise, et les fiches en annexe;
— Aucun matériel additionnel (notes de cours, examens antérieurs, etc.) n’est permis;
— Aucun appareil électronique (calculatrice, téléphone, tablette, ordinateur, etc.) n’est permis;
— Donez une seule réponse par sous-question;
— L’examen comporte 5 questions sur 10 pages valant un total de 50 points;
— La correction se base sur la clarté, l’exactitude et la concision de vos réponses, ainsi que sur
la justification pour les questions qui en requièrent une;
— À moins d’avis contraire, le langage d’assemblage utilisé est celui de l’architecture ARMv8 tel
qu’utilisé en classe; un sommaire est présenté à l’annexe B;
— La question 5 utilise le langage d’assemblage du NES tel qu’utilisé en classe; un sommaire est
présenté à l’annexe C.
b4 b3 b2 b1 b0 b4 b3 b2 b1 b0 b4 b3 b2 b1 b0
? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
0 b3 0 b1 b0 1 1 1 1 1 b4 ¬b3 ¬b2 b1 b0
b4 b3 b2 b1 b0 b4 b3 b2 b1 b0 b4 b3 b2 b1 b0
∧ ∨ ⊕
0 1 0 1 1 1 1 1 1 1 0 1 1 0 0
0 b3 0 b1 b0 1 1 1 1 1 b4 ¬b3 ¬b2 b1 b0
(b) Considérons la représentation de pixel, en niveaux de gris, stocké sur n bits, où 0 représente noir et 2n − 1 5 pts
représente blanc. Par exemple, avec n = 2, les niveaux possibles sont noir 00 , gris foncé 01 , gris pâle 10
et blanc 11 . Avec n = 8, ces 256 niveaux de gris peuvent être représentés:
page 1 sur 10
IFT209 – Programmation système Examen final Hiver 2023
Supposons que w19 contienne un pixel au format 2 bits. Nous cherchons à convertir sa représentation au
format 8 bits dans w20 comme suit:
w19 w20
Complétez les portions trouées de ces deux programmes afin qu’ils accomplissent chacun cette tâche:
programme A programme B
programme A programme B
page 2 sur 10
IFT209 – Programmation système Examen final Hiver 2023
(a) Le pictogramme « ❤ » et l’émoji « 🙊 » sont des caractères représentés, respectivement, par les codages 2 pts
UTF-8 « 11100010 10011101 10100100 » et « 11110000 10011111 10011001 10001010 ». Donnez le code
numérique Unicode associé à chacun de ces deux caractères (en hexadécimal).
276416 (obtenu de 11100010 10011101 10100100) et 1F64A16 (obtenu de 11110000 10011111 10011001 10001010)
(b) Le code numérique Unicode de la lettre accentuée « ê » est 0xEA. Donnez son codage UTF-8. 2 pts
(c) Rappelons que le codage ISO 8859-1 (Latin-1) permet de représenter les caractères dont le code numérique 2 pts
Unicode appartient à la plage 0x00 à 0xFF. Combien de caractères de cette chaîne de caractères UTF-8 sont
représentables en Latin-1? Justifiez.
11010111 10000110 11000011 10101010 01111010 11100011 10000011 10000001 00000000
3 car il y a deux caractères d’un octet, et un caractère de deux octets dont le code numérique est
inférieur ou égal à 0xFF:
11010111 10000110 11000011 10101010 01111010 11100011 10000011 10000001 00000000
(d) Rappelons que les lettres accentuées ont un code numérique dans la plage 0xC0 à 0xFF, et que le sixième 6 pts
bit de poids faible du code numérique vaut 1 si et seulement si la lettre est en minuscule. Par exemple, le
code numérique de « ê » est 111010102 (0xEA) et celui de « Ê » est 110010102 (0xCA).
Écrivez un sous-programme qui accomplit cette tâche:
Entrée: adresse d’une chaîne de caractères s sous codage UTF-8,
dont chaque caractère est d’au plus deux octets (premier et seul paramètre)
Retour: quantité de lettres accentuées en minuscule dans s
En particulier, votre sous-programme devrait retourner 2 sur la chaîne de caractères « Été à Sherbrooke ».
Vous avez accès aux macros SAVE et RESTORE.
Remarque: pour simplifier la question, vous avez la promesse qu’il n’y aura aucun caractère de trois ou quatre octets.
page 3 sur 10
IFT209 – Programmation système Examen final Hiver 2023
fouille_aux(t, x, i, j ):
si i > j alors
retourner −1 // élément pas dans le tableau
sinon
m ← (i + j) ÷ 2
si x < t[m] alors
retourner fouille_aux(t, x, i, m − 1) // l'élément est à gauche?
sinon si t[m] < x alors
retourner fouille_aux(t, x, m + 1, j ) // l'élément est à droite?
sinon
retourner m // t[m] = x, élément trouvé
fouille:
/* à compléter au besoin */
SAVE
/* à compléter */
RESTORE
/* à compléter au besoin */
fouille_aux:
/* à compléter au besoin */
SAVE
/* à compléter */
RESTORE
/* à compléter au besoin */
Remarque: ne modifiez pas l’algorithme pour le rendre itératif, il doit demeurer récursif.
page 4 sur 10
IFT209 – Programmation système Examen final Hiver 2023
(b) Expliquez ce qui se produit si on retire SAVE et RESTORE de votre code et qu’on l’appelle avec l’entrée t = [10], 2,5 pts
n = 1 et x = 15.
L’appel fouille_aux(t, 15, 0, 0) assigne « x30 ← A ». Comme 15 > t[0], l’appel fouille_aux(t,
15, 1, 0) assigne « x30 ← B ». Par la suite, chaque « ret » banche à B, ce qui crée une boucle infinie.
(c) Remplacez SAVE et RESTORE par votre propre code afin de sauvegarder uniquement le contenu des registres 2,5 pts
nécessaires, par ex. si vous n’utilisez pas x28 , alors il ne devrait pas être sauvegardé.
page 5 sur 10
IFT209 – Programmation système Examen final Hiver 2023
fouille:
stp x29, x30, [sp, -16]!
mov x29, sp
// ...
ldp x29, x30, [sp], 16
ret
fouille_aux:
stp x29, x30, [sp, -32]!
mov x29, sp
stp x19, x20, [sp, 16]
// ...
ldp x19, x20, [sp, 16]
ldp x29, x30, [sp], 32
ret
Votre résultat doit être normalisé et approximé par arrondi avec bris d’égalité vers chiffre pair (l’arrondi vu en
classe). Laissez une trace de votre démarche.
Réponse: 1,010 × 21
Démarche:
1,110
×
1,100
0,1110
+ 1,110
10,1010
On obtient 10,1010 × 2−2+2 = 10,1010 × 20 = 1,01010 × 21 . Il y a égalité entre les approximations
1,010 et 1,011. On choisit la première car elle termine par 0.
(b) Rappelons que la norme IEEE 754 représente un nombre en virgule flottante ainsi en binaire:
Par exemple, le nombre 1,5 est codé sous précision simple par « 0 01111111 10000000000000000000000 ».
(i) Donnez le codage du nombre 13,625 au format simple précision. 2,5 pts
0 10000010 10110100000000000000000
page 6 sur 10
IFT209 – Programmation système Examen final Hiver 2023
(ii) Vrai ou faux: afin de convertir un nombre en virgule flottante du format simple vers le format double, 2,5 pts
on doit ajouter 32 zéros à sa gauche. Justifiez.
Faux, par ex. si le nombre est négatif, alors l’ajout de ces zéros engendrera un nombre positif.
Question 5: entrées/sorties
Rappelons les trois types d’interruptions du NES, du plus au moins prioritaire:
(a) Le NES Mouse209 est un périphérique fictif du NES. Il s’agit d’une souris munie de deux boutons: 7 pts
b7 b6 b5 b4 b3 b2 b1 b0
Première lecture: — — — — — — — —
Deuxième lecture: bouton droit appuyé? bouton gauche appuyé? — — — — — —
Troisième lecture: haut = 1, bas = 0 déplacement vertical (entier non signé de 7 bits)
Quatrième lecture: gauche = 1, droite = 0 déplacement horizontal (entier non signé de 7 bits)
Complétez le code ci-dessous afin que le curseur se déplace horizontalement selon l’information fournie par
la souris. Vous n’avez pas à gérer les débordements hors de l’écran; le curseur peut réapparaître de l’autre
côté. Vous n’avez pas à gérer le déplacement vertical.
Le curseur doit également changer d’apparence. Il est représenté graphiquement par la tuile 129 lorsque
le bouton gauche est appuyé, et par la tuile 128 sinon.
page 7 sur 10
IFT209 – Programmation système Examen final Hiver 2023
point_entree: ; point_entree() {
lda #%00000000 ; Désactiver temporairement les interruptions NMI
sta $2000 ;
;
ldx #$FF ;
txs ; Initialiser la pile d'exécution
;
jsr init ; Initialiser les variables
;
lda #%10011000 ; Réactiver les interruptions NMI et
sta $2000 ; choisir les tables de tuiles
lda #%00010000 ;
sta $2001 ; Activer les tuiles
;
boucle: ; while (true) { }
jmp boucle ; }
;
gestion: ; gestion()
; {
SAVE ; /* empiler a, x et y */
jsr deplacer ; deplacer()
jsr afficher ; afficher()
RESTORE ; /* dépiler a, x et y */
rti ; }
;
init: ; init()
lda #100 ; {
sta posX ; posX = 100
sta posY ; posY = 100
lda #0 ;
sta btnGauche ; btnGauche = 0
sta btnDroite ; btnDroite = 0
rts ; }
;
;; Déplacer curseur selon ;
;; l'état du NES Mouse209 ;
deplacer: ; deplacer()
; {
;; À COMPLÉTER ;
; }
;
;; Afficher le curseur ;
afficher: ; afficher()
; {
;; À COMPLÉTER ; ; Ordre: pos. verticale, identifiant, attributs,
; pos. horizontale
lda #$05 ; Envoi par accès direct à la mémoire (DMA)
sta $4014 ; de la plage $0500 à $05FF
;
;; À COMPLÉTER ;
; }
;
page 8 sur 10
IFT209 – Programmation système Examen final Hiver 2023
deplacer:
;; Demander état souris
lda #1
sta $4017
lda #0
sta $4017
;; Bouton gauche?
lda $4017
lda $4017
and #%01000000
sta btnGauche
ldx #0
deplacer_decalage:
lsr btnGauche
inx
cpx #6
bne deplacer_decalage
;; Curseur
lda $4017
lda $4017
tax
and #%1000000
cmp #%1000000
txa
and #%0111111
bne deplacer_suite
deplacer_gauche:
eor #%1111111
clc
adc #1 ; a = -a // complément à deux
deplacer_suite:
clc
adc posX
sta posX
rts
afficher:
lda posY
sta $0500
lda #128
ora btnGauche
sta $0501
lda #%00000000
sta $0502
lda posX
sta $0503
lda #$05
sta $4014
rts
page 9 sur 10
IFT209 – Programmation système Examen final Hiver 2023
(b) Rappelons que l’intervalle de rafraîchissement vertical (VBLANK) se produit à intervalle régulier. On peut en 3 pts
être averti par une interruption (NMI) ou en inspectant le bit de poids fort à l’adresse 200216 . Considérons
cette légère modification du code précédent:
Le déplacement du curseur se fait maintenant trop rapidement par rapport à l’affichage. Expliquez comment
ralentir la lecture de l’état de la souris afin qu’elle se fasse à la même cadence que l’affichage.
page 10 sur 10
Annexe A:
Fiches récapitulatives
8. Programmation structurée
Séquence Itération
▶ Composition séquentielle d’instructions ▶ Exécution répétée d’instructions (while, do while, for, ...)
▶ Une instruction de haut niveau peut nécessiter plusieurs ins- ▶ Implémentation: branchements arrière, et parfois avant:
tructions de bas niveau; par ex. « x19 *= 7 » devient:
while (cond(xd, xn)) { boucle:
mov x20, 7 // code cmp xd, xn
mul x19, x19, x20 } b.¬cond fin
// code
Sélection b boucle
fin:
▶ Exécution conditionnelle d’instructions (if, switch, ...)
▶ Implémentation: branchements avant: Sous-programmes
if (cond(xd, xn)) { si: ▶ Permettent de modulariser le code en sous-routines
// code si
}
cmp xd, xn
▶ Registres partagés par programme et sous-programmes
b.¬cond sinon
else { // code si ▶ Arguments: passés par valeur ou adresse dans x0 –x7 (en ordre)
// code sinon b fin
} sinon: ▶ Appel: « bl sprog » assigne x30 ← pc+4 et branche à sprog:
// code sinon
fin: ▶ Retour: « ret » branche vers l’adresse de retour x30
▶ Conditions multiples: obtenues avec plusieurs sélections ▶ Sauvegarde: l’appelé doit rétablir les registres x19 à x30
Instructions (text)
▶ Contient les données allouées dynamiquement: structures de
Données statiques données, objets, etc.
Initialisées, en lecture seule (rodata)
Pile d’exécution.
Initialisées (data)
▶ Stocke les données temporaires lors d’appel de sous-prog.
Non initialisées (bss) ▶ Données empilées à l’appel et dépilées au retour
▶ Pointeur de pile: sp contient l’adresse du sommet de la pile
Données dynamiques
Tas
▶ Empiler: décrémenter sp + stocker avec stp xd, xn, a
↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ▶ Dépiler: incrémenter sp + charger avec ldp xd, xn, a
Récursion.
sp (pointeur de pile)
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
▶ Implémentée par: appels de sous-prog. + usage de la pile
Pile ▶ Récursion trop profonde: erreur car la pile est bornée
FFFF · · · FFFF16 ▶ Solution (partielle): empiler le moins de données possibles
Arithmétique (entiers).
▶ Les codes de condition sont modifiés par cmp, adds, adcs, subs, sbcs et negs
▶ À cette différence près, adds, adcs, subs, sbcs et negs se comportent respectivement comme add, adc, sub, sbc et neg
▶ Instructions, où i est une valeur immédiate de 12 bits et j est une valeur immédiate de 6 bits:
Conditions de branchement.
▶ Codes de condition: N (négatif), Z (zéro), C (report), V (débordement)
▶ C indique aussi l’absence d’emprunt lors d’une soustraction
▶ Conditions de branchement:
Branchement.
▶ Instructions de branchement, où j est une valeur immédiate de 6 bits:
Autres instructions.
Code d’op. Syntaxe Effet Exemple
csel csel rd, rn, rm, cond si cond: rd ← rn , sinon: rd ← rm csel x19, x20, x21, eq
Registres Utilisation
d0 – d7 registres d’arguments et de retour de sous-programmes
d8 – d15 registres sauvegardés par l’appelé
d16 – d31 registres sauvegardés par l’appelant
Données statiques.
Valeurs immédiates.
▶ #: valeur numérique, sans #: adresse
▶ $: valeur hexadécimale
expression valeur
▶ %: valeur binaire
#5 510
▶ Exemples: #$FF FF16
#%00010011 000100112
$FF adresse FF16
Modes d’adressage.
Nom. Syntaxe Adresse Exemple
absolu i i lda $D010
i, x i+x lda $D010, x
indexé par x
etiq, x etiq + x lda tab, x
i, y i+y lda $D010, y
indexé par y
etiq, y etiq + y lda tab, y
Accès mémoire.
▶ Instructions, où mem1 [a] dénote l’octet situé à l’adresse a de la mémoire principale:
Logique.
Code d’op. Syntaxe Effet Exemple
asl asl adr décalage logique de mem1 [adr] d’un asl var
bit à gauche (directement en mémoire)
lsr lsr adr décalage logique de mem1 [adr] d’un lsr var
bit à droite (directement en mémoire)
and #i a←a∧i and #%00100011
and
and adr a ← a ∧ mem1 [adr] and var
ora #i a←a∨i ora #%00100011
ora
ora adr a ← a ∨ mem1 [adr] ora var
eor #i a←a⊕i eor #%00100011
eor
eor adr a ← a ⊕ mem1 [adr] eor var
Comparaisons et branchements.
Code d’op. Syntaxe Effet Exemple
cmp #i compare a et i cmp #0
cmp
cmp adr compare a et mem1 [adr] cmp var
cpx #i compare x et i cpx #0
cpx
cpx adr compare x et mem1 [adr] cpx var
cpy #i compare y et i cpy #0
cpy
cpy adr compare y et mem1 [adr] cpy var
beq beq etiq branche à etiq: si = beq boucle
bne bne etiq branche à etiq: si ̸= bne boucle
jmp jmp etiq branche à etiq: jmp boucle
jsr jsr etiq branche au sous-programme etiq: jsr func
et empile l’adresse de retour
rts rts branche à l’adresse de retour d’un rts
sous-programme
rti rti branche à l’adresse de retour d’une rti
interruption