Salta ai contenuti

UDA 1 — Registri, istruzioni e indirizzamenti

6 ore (2 di teoria + 4 di laboratorio) · Settimane 2-3

Al termine di questa unità:

  • conosci i registri del G80 e sai scegliere quello giusto per ogni dato;
  • sai scrivere istruzioni di trasferimento (LD), aritmetiche (ADD, SUB, INC, DEC) e logiche (AND, OR, XOR, CPL, CP);
  • sai leggere i flag e prevedere il loro valore prima di premere Esegui;
  • riconosci i modi di indirizzamento in un listato;
  • usi etichette, costanti e le direttive di base (.org, .db, .dw, .ds, .ascii);
  • hai completato l’Esercizio 1 e la scheda di traccia dell’esecuzione.

Piano delle due settimane — Incontro 1 (3 h): registri, LD, aritmetica, flag. Incontro 2 (3 h): logica, indirizzamenti, etichette/direttive, laboratorio e verifica formativa.


Il G80 ha pochi registri, tutti dentro la CPU, velocissimi:

RegistroDimensioneUso tipico
A8 bitaccumulatore: risultati, operazioni aritmetiche/logiche, I/O
F8 bitflag: S Z 5 H 3 V N C (li studiamo al §5)
B C D E H L8 bitregistri generici; a coppie formano BC, DE, HL (16 bit)
HL16 bitcoppia “preferita” per puntare la memoria ((HL))
PC16 bitprogram counter: indirizzo della prossima istruzione
SP16 bitstack pointer: punta alla cima dello stack (UDA 3)
IX IY16 bitregistri indice: indirizzamento con spiazzamento (IX+3)

Regola d’oro: i dati a 8 bit si mettono in un registro a 8 bit; gli indirizzi (16 bit) in una coppia. Il registro A è il protagonista di quasi tutte le operazioni.

Nel simulatore apri il pannello Registri e flag e tieni d’occhio A e PC mentre esegui con Passo: è il modo più veloce per capire cosa fa ogni istruzione.


Una riga di assembly ha questa forma:

etichetta: mnemonico operando1, operando2 ; commento
  • l’etichetta è opzionale e indica un indirizzo (per salti e dati);
  • il mnemonico (LD, ADD, JP…) è l’operazione;
  • gli operandi sono registri, numeri o indirizzi;
  • il commento inizia con ; e serve a te e ai tuoi compagni (scrivilo!).

Dall’assembly al codice macchina: ogni istruzione diventa 1, 2 o 3 byte. Ecco coppie reali (puoi verificarle con il disassemblaggio nel simulatore):

AssemblyByteNote
LD A, 0x553E 55il valore segue il codice
LD C, 0x100E 10
ADD A, B80registro: un solo byte
SUB 0x04D6 04
LD (0x8000), A32 00 80indirizzo a 16 bit, prima il byte basso
HALT76ferma la CPU

ld a, 0x55 ; immediata: A = 0x55
ld b, a ; registro: B = A
ld hl, 0x1234 ; 16 bit: HL = 0x1234
ld (0x0010), a ; diretta: scrive A nella cella 0x0010
ld a, (0x0010) ; diretta: legge la cella 0x0010 in A
ld (hl), a ; indiretta: scrive nella cella puntata da HL
ld a, (hl) ; indiretta: legge dalla cella puntata da HL
ld (ix+3), 0xAB ; indicizzata: cella IX+3

Attenzione a due cose:

  1. le parentesi significano “il contenuto della cella”: ld a, 0x0010 mette in A il numero 0x0010, ld a, (0x0010) mette in A il contenuto della cella 0x0010 — è l’errore classico!
  2. LD è un semplice trasferimento: non modifica i flag.

ld a, 0x15
add a, 0x0B ; A = 0x20
sub 0x04 ; A = 0x1C
inc a ; A = 0x1D
dec b ; B = B - 1
IstruzioneSignificatoFlag modificati
ADD A, n / ADD A, rA = A + operandoZ S H V N C
SUB n / SUB rA = A - operandoZ S H V N C
INC r / DEC r+1 / −1Z S H V N — non C
ADC / SBCsomma/sottrazione con carrytutti

Esempi da prevedere prima di eseguire (poi verifica col simulatore):

OperazioneACZHVN
0x15 + 0x0B0x2000100
0xFF + 0x010x0011100
0x7F + 0x010x8000110
0x08 − 0x040x0400001

Il half-carry H è il “riporto dal 4° bit”: serve per l’aritmetica in decimale. Il V in aritmetica indica overflow con segno (es. 0x7F + 1 = 0x80: +127 +1 “sfora” il massimo rappresentabile). Attenzione: il G80 non ha l’istruzione DAA dello Z80: se la incontri in esempi Z80, qui è illegale.


and 0x0F ; tiene solo i 4 bit bassi di A (maschera)
or 0x80 ; accende il bit 7
xor 0xFF ; inverte tutti i bit di A
cpl ; come xor 0xFF, ma su A sola
cp 0x20 ; confronta A con 0x20 (senza salvare)
IstruzioneEffetto su AUso tipico
AND nbit a bit “e”spegnere i bit (mascherina di 0)
OR nbit a bit “o”accendere i bit (mascherina di 1)
XOR nbit a bit “xor”invertire i bit scelti
CPLA = ~Ainvertire tutti i bit
CP nnessunoconfrontare: è una sottrazione che non salva

Dopo le istruzioni logiche: C = 0 e N = 0; V diventa la parità (1 se il numero di bit a 1 è pari). CP invece imposta i flag come una sottrazione: è così che si decide “minore / uguale / maggiore” (lo useremo nei salti, UDA 2).

Esempio di maschera sui LED: mostra sui LED solo i bit pari degli interruttori.

in a, (0x90) ; leggi gli interruttori
and 0x55 ; 0101 0101: tiene i bit 0, 2, 4, 6
out (0x20), a ; mostrali sui LED

Dopo ogni operazione i flag raccontano com’è andata. Nel simulatore sono il gruppo verde/nero accanto a F (S Z 5 H 3 V N C; i bit “5” e “3” sono interni e si ignorano).

FlagNomeVale 1 quando…
Ssegnoil bit 7 del risultato è 1 (risultato “negativo”)
Zzeroil risultato è zero
Hhalf-carryc’è riporto/borrow dal 4° bit
Voverflow / paritàoverflow con segno / parità pari (logica)
Nsottrazionel’ultima operazione era una sottrazione
Ccarryc’è riporto/borrow “in uscita”

Perché ci interessano? Perché i salti condizionati (UDA 2) leggono proprio i flag: “salta se zero”, “salta se carry”, “salta se minore”… Un programmatore assembly pensa in flag.


Riconoscerli è metà del lavoro di lettura di un listato:

ModoEsempioDove sta il dato
implicitainc a, cplnel registro sottinteso (A)
immediatald a, 0x0Fdentro l’istruzione
registrold b, ain un altro registro
indirettald (hl), anella cella puntata da HL
direttald (0x0010), hlnella cella indicata dall’istruzione
relativajr saltaa un indirizzo vicino (spiazzamento)
indicizzatald (ix+3), 0xABa IX + spiazzamento

VAL1 = 0x15 ; costante (equate): non occupa memoria
.org 0x0100 ; il codice inizia qui (facoltativo)
inizio:
ld a, VAL1 ; usa la costante
halt
.org 0x0010 ; dati in una zona a parte
dati: .db 0x0F, 0x80 ; due byte di dati
punto: .dw 0x1234 ; una parola (16 bit): 34 12
spazio: .ds 6 ; riserva 6 byte
testo: .ascii /Ciao/ ; i caratteri "Ciao" in memoria
DirettivaCosa fa
.orgfissa l’indirizzo di partenza (il “punto”)
.dbinserisce uno o più byte
.dwinserisce parole a 16 bit (indirizzi)
.dsriserva N byte
.asciiinserisce una stringa (delimitata da /…/ o "…")

Le etichette sono indirizzi con un nome; le costanti (NOME = valore) sono comodità del programmatore. Trucco tipico: ld b, fine - inizio per calcolare una lunghezza, perché la differenza di due etichette è un numero.


Apri l’esempio nella raccolta (o incollalo dall’editor degli esempi) ed esegui Passo per passo con la memoria aperta. Verifica queste affermazioni:

  1. dopo ld hl, 0x1234 e ld (0x0010), hl, nelle celle 0x0010 e 0x0011 ci sono 34 e 12 (prima il byte basso);
  2. ld a, (0x0010) mette in A il valore 0x34; con inc a diventa 0x35;
  3. ld (hl), a scrive 0x35 nella cella 0x1234;
  4. ld (ix+3), 0xAB scrive 0xAB nella cella 0x0203.

Consegna: per ogni riga dell’esempio, indica il modo di indirizzamento.

  1. esegui con Passo fino a dopo add a, b: A vale 0x20, C = 0, H = 1 (riporto dal 4° bit: 5 + 11 = 16!). Chiediti: perché H è 1 anche se il risultato “sta in un byte”?
  2. prosegui: sub c → A = 0x1B con C = 0 e N = 1;
  3. cp d con D = 0x20 → C = 1 (0x1B < 0x20) e il jr c salta a minore: A = 1.

Consegna: cambia i valori (B, C, D) e prevedi su carta flag e salto, poi verifica.

Apri esercizi/01-somma.asm: manca una riga (il TODO). Completa, assembla ed esegui.

  • Verifica: con VAL1 = 0x15 e VAL2 = 0x0B → A = 0x20.
  • Poi cambia VAL1/VAL2 (es. 0xFF e 0x02) e spiega cosa cambia nei flag.
  • Confronta con la soluzione solo dopo aver provato.
  1. scrivi ed esegui questo programma (la cella 0x0010 è usata come “interruttore”):
.org 0x0100
ld a, (0x0010) ; legge un byte dalla memoria
out (0x20), a ; lo mostra sui LED
halt
  1. premi Assembla & Carica, poi fermati prima di eseguire;
  2. apri la memoria, vai a 0x0010, clicca il byte e inserisci 0x0F;
  3. ora premi Esegui (senza Reset): i LED si accendono secondo il valore che hai scritto;
  4. ripeti con 0xAA e 0x55.

Consegna: spiega perché la modifica va fatta dopo il caricamento e prima dell’esecuzione.


Completa le tabelle senza eseguire (poi controlla col simulatore o con la soluzione).

Listato A

ld a, 0x05
ld b, 0x03
add a, b
sub 0x04
halt
IstruzioneA dopoCZSHVN
ld a, 0x05
ld b, 0x03
add a, b
sub 0x04

Listato B

ld a, 0xFF
add a, 0x01
halt
IstruzioneA dopoCZSHVN
ld a, 0xFF
add a, 0x01
Mostra la soluzione

Listato A — A = 0x05 → 0x08 → 0x04. add a, b: C=0 Z=0 S=0 H=0 V=0 N=0 (5+3=8, nessun riporto di nibble); sub 0x04: C=0 Z=0 S=0 H=0 V=0 N=1.

Listato B — A = 0x00. add a, 0x01: C=1 (riporto), Z=1 (risultato zero), S=0, H=1 (0xF+0x1 → riporto dal nibble), V=0 (−1+1=0, nessun overflow con segno), N=0.


“Solo i bit pari” — leggi gli interruttori e mostra sui LED solo i bit in posizione pari (0, 2, 4, 6). Suggerimento: serve una maschera con AND.

Poi la variante: inverti i bit pari e lascia invariati i dispari (quale operazione serve?).


  1. Quale registro contiene l’esito delle operazioni? Dove stanno i flag?
  2. Che differenza c’è tra ld a, 0x0010 e ld a, (0x0010)?
  3. Perché è utile che LD non modifichi i flag?
  4. Che differenza c’è tra sub b e cp b?
  5. Dopo ld a, 0xF0 + add a, 0x20: quanto vale A? Quali flag si attivano?

📎 I file .asm di esempi ed esercizi si scaricano dalla pagina Materiali.

  • Compito: completa l’Esercizio 1 e le due tabelle di traccia; riscrivi l’esempio 02 con valori scelti da te e prevedi i flag prima di eseguire.
  • Pre-lettura: manuale, sezioni Sintassi e Registri e flag.
  • Materiali: esempi 01-indirizzamenti.asm, 02-somma-e-flag.asm; esercizio esercizi/01-somma.asm (+ soluzione).
  • Prossima unità: il controllo del flusso — salti, confronti e cicli (UDA 2).