EMU8086 (Assembly 8086) – Guida completa

Approfondimenti, scopi didattici, metodo di lavoro, esempi ed esercizi

Obiettivo: capire davvero cosa succede “sotto”, con registri, memoria, stack e istruzioni.
Consiglio: lavora sempre con Debug Step-by-Step e annota registri e flag.
1) Che cos’è EMU8086 e perché lo usiamo

EMU8086 è un ambiente didattico che permette di scrivere, assemblare, eseguire e debuggare programmi in Assembly per l’architettura Intel 8086 (16 bit), osservando in tempo reale registri, memoria, stack e flag. È perfetto per allenare la mentalità “a basso livello”: ogni istruzione ha un costo, un effetto preciso, e spesso cambia anche i flag.

Scopi didattici principali
  • Capire il modello CPU–memoria (fetch–decode–execute).
  • Leggere/scrivere dati in registri e in RAM.
  • Usare lo stack (CALL/RET, PUSH/POP) e comprenderne il comportamento.
  • Interpretare i flag (ZF, CF, SF, OF) dopo operazioni aritmetiche/logiche.
  • Capire differenze tra istruzioni e indirizzamenti (immediato, diretto, indiretto, indicizzato).
  • Allenare precisione e debugging: “una riga = un effetto”.
Cosa NON è
  • Non è “programmare più veloce”: è programmare più vicino alla macchina.
  • Non è “copia/incolla”: qui l’errore di 1 carattere può cambiare tutto.
  • Non sostituisce C/Python: serve per capire le basi che quei linguaggi nascondono.

Concetti chiave da tenere sempre in mente
Registri (16 bit)
AX, BX, CX, DX, SI, DI, BP, SP, IP + segmenti
  • AX: accumulatore (AL/AH).
  • CX: contatore (LOOP, REP).
  • SP/BP: stack pointer / base pointer.
Memoria segmentata
Indirizzo fisico: segmento:offset
  • CS:IP indica dove sta eseguendo la CPU.
  • DS per i dati, SS:SP per lo stack.
  • Formula: segmento * 16 + offset.
Flag (stato)
ZF, CF, SF, OF…
  • ZF: risultato zero.
  • CF: carry/borrow (unsigned).
  • OF: overflow (signed).
2) Metodo di lavoro: come si usa EMU8086 in modo “da laboratorio”
Regola d’oro
Non lanciare subito “Run”. Fai sempre Step e controlla registri + flag dopo ogni blocco.
Workflow consigliato
  1. Scrivi il codice in blocchi piccoli (5–15 istruzioni) e con etichette chiare.
  2. Assembla e risolvi gli errori sintattici.
  3. Step-by-step e verifica: AX/BX/CX/DX, ZF/CF/OF, eventuale memoria.
  4. Solo alla fine usa Run per l’esecuzione completa.
Checklist di debug
  • Byte vs word: sto usando AL/AX correttamente?
  • Signed vs unsigned: sto usando i salti giusti (JL/JG vs JB/JA)?
  • Ho inizializzato registri e variabili prima di usarli?
  • Sto controllando i flag dopo ADD/SUB/CMP?
  • In un loop: CX si sta aggiornando correttamente?

Struttura tipica di un programma (semplice)
org 100h

start:
    mov ax, 0000h
    mov bx, 0000h
    mov cx, 0000h
    mov dx, 0000h

    ; qui il tuo codice

exit:
    ret
3) Approfondimenti 8086: addressing, stack, salti e output
A) Addressing (come punti la memoria)
  • mov ax, 1234h immediato
  • mov ax, [2000h] diretto
  • mov ax, [bx] indiretto
  • mov ax, [bx+si] base+index
  • mov al, [si+10] indicizzato
Suggerimento: scrivi l’indirizzo che stai calcolando prima di eseguire.
B) Stack (CALL/RET, PUSH/POP)
  • PUSH salva e SP scende.
  • POP ripristina e SP sale.
  • CALL salva l’indirizzo di ritorno sullo stack.
  • RET riprende l’indirizzo e torna.

C) CMP + salti condizionati (signed)
org 100h

mov ax, 0007h
cmp ax, 000Ah
jl  minore
je  uguale
jg  maggiore

minore:
    ret
uguale:
    ret
maggiore:
    ret
Per unsigned usa JB/JA al posto di JL/JG.
D) Output rapido (stile DOS): stampa un carattere
org 100h

mov ah, 02h
mov dl, 'A'
int 21h

mov dl, 0Dh
int 21h
mov dl, 0Ah
int 21h

ret
4) Esercizi guidati (dal facile al ragionato)
Regola
Ogni esercizio: (1) previsione su carta, (2) verifica in EMU8086 con Step, (3) tabellina registri/flag.
Esercizio 1: somma e flag
org 100h

mov al, 0FFh
add al, 01h

; Domande:
; 1) AL vale 00h?
; 2) ZF = 1?
; 3) CF = 1?

ret
  • Fai Step e annota AL, ZF, CF.
  • Ripeti con AL=0FEh e confronta.
Esercizio 2: massimo tra due numeri (unsigned)
org 100h

mov ax, 000Ah
mov bx, 0007h

cmp ax, bx
ja  ax_maggiore

mov cx, bx
jmp fine

ax_maggiore:
mov cx, ax

fine:
ret
  • Cambia AX e BX e verifica CX.
  • Prova una versione signed con JL/JG.
Esercizio 3: somma di un array (byte)
org 100h

arr db 5, 10, 20, 1, 2
len equ 5

mov si, 0
mov cx, len
xor ax, ax

somma:
    mov bl, [arr + si]
    add al, bl
    inc si
    loop somma

ret
  • Prevedi la somma prima di eseguire.
  • Osserva SI, CX e AL ad ogni giro.
Esercizio 4: subroutine + stack
org 100h

mov ax, 0003h
mov bx, 0004h
call somma2
ret

somma2:
    add ax, bx
    ret
  • Fai Step su CALL e RET e osserva SP.
  • Verifica che il ritorno sia corretto.
Esercizio 5: mini-progetto con output
Somma 3 valori: se somma ≥ 20 stampa 'H', altrimenti 'L'.
org 100h

a db 7
b db 8
c db 6

xor ax, ax
mov al, [a]
add al, [b]
add al, [c]

cmp al, 20
jb  stampa_L

stampa_H:
    mov ah, 02h
    mov dl, 'H'
    int 21h
    jmp fine

stampa_L:
    mov ah, 02h
    mov dl, 'L'
    int 21h

fine:
    mov ah, 02h
    mov dl, 0Dh
    int 21h
    mov dl, 0Ah
    int 21h

ret
Variante
Aggiungi un quarto valore e aggiorna la soglia. Poi fai una versione che stampa anche un numero (solo se già visto in classe).
Riepilogo rapido (da ripetere a voce)
  • EMU8086 serve per vedere CPU e memoria: registri, flag, stack, RAM.
  • Metodo: scrivi → assembla → Step → controlla registri/flag → correggi.
  • CMP + Jcc è la base della logica: attenzione a signed vs unsigned.
  • Memoria segmentata: DS (dati) e SS:SP (stack).
  • Per imparare: esercizi brevi, verificabili, con previsione e verifica al debugger.
5) Esercitiamoci con EMU8086

Clicca un bottone per aprire l’esercizio con il codice completo.