UDA 3 — Memoria, stack e sottoprogrammi
6 ore (2 di teoria + 4 di laboratorio) · Settimane 5-6
Obiettivi
Sezione intitolata “Obiettivi”Al termine di questa unità:
- organizzi vettori e tabelle in memoria (
.db,.dw) e li scorri conHL/IX; - copi (e riempi) blocchi di memoria con
LDIR; - conosci lo stack:
PUSH/POP,SP, dove finiscono davvero i byte; - scrivi e chiami sottoprogrammi (
CALL/RET), anche annidati; - passi parametri e ricevi valori di ritorno secondo una convenzione;
- hai completato gli Esercizi 3 e 4 e sostieni la prova scritta n. 1.
Piano delle due settimane — Incontro 1 (3 h): memoria, vettori,
LDIR+ Esercizio 4. Incontro 2 (3 h): stack, sottoprogrammi + Esercizio 3 e prova scritta.
1. La memoria è un vettore di byte
Sezione intitolata “1. La memoria è un vettore di byte”La memoria del G80 è fatta di 65536 celle (0x0000–0xFFFF), ognuna da 1 byte. Un “vettore” (o tabella) è semplicemente una zona di memoria con dati in fila:
dati: .db 10, 20, 30, 40, 50 ; 5 byte consecutiviimporti: .dw 100, 250, 40 ; 3 parole (6 byte): 64 00 FA 00 28 00Due cose da ricordare:
- le etichette sono indirizzi:
dati+3è l’indirizzo del 4° byte; - le parole
.dwsono salvate little-endian: prima il byte basso (100 =0x0064→ in memoria64 00).
Un vettore di dati si scorre con un puntatore (HL, IX) e un contatore (B con DJNZ):
ld hl, dati ; puntatore all'inizio ld b, 5 ; quanti elementi xor a ; accumulatore a 0ciclo: add a, (hl) ; somma l'elemento puntato inc hl ; avanza al prossimo djnz ciclo haltdati: .db 10, 20, 30, 40, 50Risultato: somma 10+20+30+40+50 = 150 = 0x96 in A (provalo!).
Tabelle a 16 bit
Sezione intitolata “Tabelle a 16 bit”Per leggere una parola servono due letture (byte basso, poi alto). Con IX come puntatore
si legge comodamente con (ix+0) e (ix+1):
ld ix, importi ld hl, 0 ; totale a 16 bit ld b, 3ciclo: ld e, (ix+0) ; byte basso ld d, (ix+1) ; byte alto add hl, de ; totale = totale + importo inc ix inc ix ; avanza di 2 (una parola) djnz ciclo haltimporti: .dw 100, 250, 40Risultato: 100 + 250 + 40 = 390 = 0x0186 in HL.
Nota sui flag:
ADD HL, DEè una somma a 16 bit e aggiorna soloH,N,C(Z,S,Vrestano invariati). Per accorgersi di un “riporto” a 16 bit si guardaC.
2. Copiare blocchi: LDIR
Sezione intitolata “2. Copiare blocchi: LDIR”Spostare dati un byte per volta è noioso: la CPU ha un’istruzione fatta apposta.
ld hl, origine ; da dove ld de, destinazione ; dove ld bc, 16 ; quanti byte ldir ; copia finché BC != 0LDIR ripete automaticamente questi passi:
- copia il byte
(HL)in(DE); - incrementa
HLeDE; decrementaBC; - se
BC ≠ 0ripete; altrimenti prosegue.
Varianti utili: LDI (una sola iterazione), LDDR (copiando all’indietro, utile se le zone
si sovrappongono). Per riempire una zona si usa spesso LDIR con origine fissa… oppure un
semplice ciclo di LD (HL), n.
3. Lo stack
Sezione intitolata “3. Lo stack”Lo stack è una zona di memoria gestita in modalità LIFO (last in, first out):
l’ultimo valore inserito è il primo a uscire. Il registro SP punta alla cima.
| Istruzione | Cosa succede |
|---|---|
push af | SP = SP − 1; (SP) = A; SP = SP − 1; (SP) = F |
push bc | come sopra, con B (alto) e C (basso) |
pop af | F = (SP); SP = SP + 1; A = (SP); SP = SP + 1 |
pop bc | C = (SP), B = (SP+1), poi SP += 2 |
Verifica concreta — esegui questo programma e guarda la memoria da 0xFFFB:
ld sp, 0xFFFF ; buona norma: fissa la cima dello stack ld a, 0x12 ld b, 0x34 push af push bc haltDopo l’esecuzione: SP = 0xFFFB e nelle celle:
0xFFFB = 00 (C) · 0xFFFC = 34 (B) · 0xFFFD = 00 (F) · 0xFFFE = 12 (A).
Regole d’oro:
- pareggia sempre i
PUSHcon iPOP: lo stack deve tornare al punto di partenza; - lo stack cresce verso il basso (da
0xFFFFverso0x0000): fissareSP = 0xFFFFall’inizio del programma mette lo stack “in cima” alla memoria; PUSH/POPnon modificano i flag (salvarli è proprio il loro mestiere!).
Perché “salvare i flag”? Perché PUSH AF conserva insieme risultato e flag: è il modo
standard per non rovinare il lavoro del chiamante (lo vedrai tra un attimo).
4. Sottoprogrammi: CALL e RET
Sezione intitolata “4. Sottoprogrammi: CALL e RET”Un sottoprogramma (subroutine) è un blocco di codice riusabile, chiamato per nome:
ld a, 0x15 call raddoppia ; chiama la subroutine halt ; qui A = 0x2A
raddoppia: add a, a ; A = A * 2 ret ; torna al chiamanteCosa fanno davvero:
CALL nome=PUSHdell’indirizzo di ritorno +JP nome(3 byte, salto a 16 bit);RET=POPdell’indirizzo di ritorno + salto lì.
Ecco perché lo stack serve: a ogni CALL si “impila” il punto da cui si dovrà riprendere.
Le chiamate possono annidarsi (una subroutine che ne chiama un’altra): lo stack tiene
l’ordine, e i RET risalgono la catena all’indietro.
Convenzione: chi salva cosa?
Sezione intitolata “Convenzione: chi salva cosa?”Un contratto chiaro evita bug difficilissimi. La convenzione che useremo:
| Ruolo | Regola |
|---|---|
| Parametri | si passano nei registri (es. valore in A, indirizzo in HL) |
| Valore di ritorno | in A (8 bit) o HL (16 bit) |
| Registri interni | la subroutine salva con PUSH/POP quelli che usa ma non restituisce |
| Flag | se al chiamante servono, la subroutine li preserva con PUSH AF / POP AF |
Esempio di contratto: la pausa attesa dell’Esercizio 3
attesa: ; input: nessuno push af ; output: nessuno push bc ; preserva: A, B, C, flag (SP torna com'era) ld bc, 0x2000att1: dec bc ld a, b or c jp nz, att1 pop bc pop af retSenza push af, la pausa azzererebbe A (xor/or … e il conteggio sui LED si
romperebbe!): è l’errore classico dell’Esercizio 3.
5. Laboratorio guidato
Sezione intitolata “5. Laboratorio guidato”Attività A — Esercizio 4 (Copia di un blocco)
Sezione intitolata “Attività A — Esercizio 4 (Copia di un blocco)”Apri esercizi/04-copia-blocco.asm: manca la copia vera e propria.
- Verifica:
0x0300..0x030Fuguali a0x0200..0x020F. Nel simulatore apri la memoria, vai a0x0300e controlla i 16 byte; oppure usa la variante con i dati nel sorgente:
.seg CODE (abs) .org 0x0200origine: .db 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
.org 0x0100 ld hl, 0x0200 ld de, 0x0300 ld bc, 16 ldir haltDopo l’esecuzione, in memoria: 0x0300: 01 02 03 … 10.
Consegna: modifica la variante per copiare 8 byte e poi per copiare “all’indietro”
(LDDR): in quale caso è necessario copiare all’indietro? (pensa a zone sovrapposte)
Attività B — Esercizio 3 (Contatore con ritardo)
Sezione intitolata “Attività B — Esercizio 3 (Contatore con ritardo)”Apri esercizi/03-contatore.asm: serve una subroutine attesa che preservi A.
- Verifica: i LED cambiano circa 2 volte al secondo (regola la costante
BC). - Contratto da rispettare: input nessuno, output nessuno, preserva
A,BCe i flag. - Confronta con la soluzione solo dopo aver capito l’effetto di
push af/pop af.
Attività C — Contare gli elementi “grandi” di un vettore
Sezione intitolata “Attività C — Contare gli elementi “grandi” di un vettore”Scrivi un programma che conta quanti valori di un vettore sono ≥ 100:
ld hl, valori ld b, 6 ld c, 0 ; contatore dei "grandi"ciclo: ld a, (hl) cp 0x64 ; 0x64 = 100 jr c, piccolo ; < 100 ? inc c ; no: contalopiccolo: inc hl djnz ciclo ld a, c ; risultato in A haltvalori: .db 10, 200, 100, 99, 150, 30Verifica: i valori ≥ 100 sono 200, 100, 150 → A = 3. Prova con altri vettori.
Consegna: adatta il programma per contare i valori dispari (suggerimento: AND 1).
6. Prova scritta n. 1
Sezione intitolata “6. Prova scritta n. 1”In coda a questa unità è prevista la prima verifica sommativa (1 ora): tracciamento di codice, completamento di frammenti e domande su flag, stack e sottoprogrammi. La trovi nella pagina “UDA 3 — Esempio di prova scritta n. 1” (con soluzioni per il docente): usala come palestra, poi il docente prepara la versione per la classe.
7. Autoverifica
Sezione intitolata “7. Autoverifica”- Con
HL = 0x1234, dove puntaHL+2? E cosa contiene(HL)in una tabella.dw? - Quali passi esegue
LDIRa ogni iterazione? Quando si ferma? - Cosa fa esattamente
PUSH BC? E dopoPOP BC, dov’èSP? - Che differenza c’è tra
CALLeJP? Cosa finisce sullo stack? - La tua subroutine usa
AeBcome registri di lavoro e restituisce il risultato inA: quali registri devi salvare conPUSH/POP, e perché?
8. Compiti e materiali
Sezione intitolata “8. Compiti e materiali”📎 I file
.asmdi esempi ed esercizi si scaricano dalla pagina Materiali.
- Compito: completa gli Esercizi 3 e 4; prova la variante
LDDR; risolvi la prova scritta di esempio senza guardare le soluzioni. - Pre-lettura: manuale, sezioni Memoria e Esempi multi-file.
- Materiali: esercizi
03-contatore.asme04-copia-blocco.asm(+ soluzioni); esempio03-led-contatore.asmper la pausa. - Prossima unità: ingressi e uscite — le periferiche di base (UDA 4).