UDA 3 — Esempio di prova scritta n. 1
Durata: 1 ora · Punteggio: 10 punti · Argomenti: UDA 1-3 (istruzioni e flag, controllo del flusso, memoria, stack, sottoprogrammi)
Nota per il docente: questa è una prova di esempio (con soluzioni richiudibili in fondo). Per la classe si consiglia la consueta prassi: varianti con valori diversi.
Sezione A — Traccia l’esecuzione (4 punti)
Sezione intitolata “Sezione A — Traccia l’esecuzione (4 punti)”Dato il listato:
ld sp, 0xFFFF ld a, 0x3C ld b, 0x0A sub b push af pop bc haltA1. Completa la tabella (valori esadecimali; usa ”—” quando il registro non cambia):
| Istruzione | A | B | C | SP |
|---|---|---|---|---|
ld sp, 0xFFFF | ||||
ld a, 0x3C | ||||
ld b, 0x0A | ||||
sub b | ||||
push af | ||||
pop bc |
A2. Dopo push af, che cosa contiene la cella 0xFFFE? E la cella 0xFFFD?
A3. Quali flag documentati (S Z H V N C) si attivano con sub b?
A4. Perché SP passa da 0xFFFF a 0xFFFD con un solo push af?
Sezione B — Completa i frammenti (3 punti)
Sezione intitolata “Sezione B — Completa i frammenti (3 punti)”B1. Copia 20 byte da 0x0800 a 0x0900 usando LDIR:
ld hl, ______ ld de, ______ ld bc, ______ ______B2. Scrivi la subroutine somma che riceve due valori in A e B e restituisce la somma
in A, senza alterare B:
somma: ; ... retB3. Nel programma principale, chiama somma con A = 5 e B = 7 e metti il risultato in C:
ld a, 5 ld b, 7 ; ...Sezione C — Domande (3 punti)
Sezione intitolata “Sezione C — Domande (3 punti)”C1. Cos’è lo stack? Che cosa indica SP e in quale direzione “cresce”?
C2. Che cosa mette esattamente sullo stack l’istruzione CALL? E che cosa fa RET?
C3. Una subroutine usa A come registro di lavoro e restituisce il risultato in A. Il
chiamante ha in B un dato che gli serve dopo la chiamata: chi deve salvarlo, e come?
C4. Descrivi i passi di LDIR a ogni iterazione e quanto vale BC alla fine.
C5. Perché può servire LDDR al posto di LDIR? Fai un esempio concreto.
Soluzioni (per il docente)
Sezione A
Sezione intitolata “Sezione A”A1.
| Istruzione | A | B | C | SP |
|---|---|---|---|---|
ld sp, 0xFFFF | — | — | — | FFFF |
ld a, 0x3C | 3C | — | — | FFFF |
ld b, 0x0A | 3C | 0A | — | FFFF |
sub b | 32 | 0A | — | FFFF |
push af | 32 | 0A | — | FFFD |
pop bc | 32 | 32 | 22 | FFFF |
A2. 0xFFFE = 0x32 (il valore di A); 0xFFFD = 0x22 (il byte dei flag dopo sub b).
Nota: 0x22 = flag N=1 più il bit 5 interno che il simulatore mostra ma che non si
considera; i flag documentati attivi sono solo N.
A3. Solo N = 1 (è una sottrazione): S = Z = H = V = C = 0.
A4. Perché PUSH scrive due byte (prima A, poi F): ogni byte decrementa SP di 1,
quindi SP scende di 2 (da FFFF a FFFD).
Sezione B
Sezione intitolata “Sezione B”B1.
ld hl, 0x0800 ld de, 0x0900 ld bc, 20 ldirB2.
somma: add a, b ; ADD A,B non modifica B retB3.
ld a, 5 ld b, 7 call somma ; A = 12 ld c, a ; risultato in CSezione C (risposte attese, sintetiche)
Sezione intitolata “Sezione C (risposte attese, sintetiche)”C1. Zona di memoria gestita LIFO (ultimo entrato, primo uscito); SP punta alla cima;
cresce verso il basso (le PUSH decrementano SP).
C2. CALL impila l’indirizzo di ritorno (l’istruzione da cui riprendere) e salta al
sottoprogramma; RET estrae quell’indirizzo e ci salta.
C3. Il chiamante: deve salvare B prima della chiamata (push bc) e ripristinarlo dopo
(pop bc), perché la subroutine non ha obblighi verso i registri del chiamante.
(In alternativa: se il contratto della subroutine prevede “preservo B”, è lei a salvarlo.)
C4. Copia il byte (HL) in (DE); incrementa HL e DE; decrementa BC; ripete finché
BC ≠ 0. Alla fine BC = 0 (e HL/DE puntano dopo le due zone).
C5. Quando le due zone si sovrappongono e la copia “in avanti” sovrascriverebbe byte non
ancora copiati. Esempio: spostare in alto di 2 posizioni un blocco da 4 byte: 0x0800→0x0802
(con LDIR si perderebbero i primi byte).