EMU8086 — l’ambiente di simulazione
EMU8086 è un assemblatore e simulatore che emula il microprocessore Intel 8086 (compatibile x86 e AMD). Non è un semplice editor di testo: è un ambiente completo di sviluppo e debug che consente di osservare l’esecuzione del codice Assembly istruzione per istruzione.
I programmi che coinvolgono l’I/O aprono automaticamente la finestra del DOS, rendendo interattiva l’esecuzione: è possibile inserire dati da tastiera e visualizzare l’output sullo schermo — esattamente come un programma reale.
.asm nell’editor integrato.com o .exe e segnala eventuali errori di sintassiModelli di memoria — .COM e .EXE
L’8086 gestisce la memoria attraverso segmenti da 64 KB ciascuno. Il formato del file eseguibile determina come questi segmenti vengono organizzati prima dell’esecuzione.
MOV DS, valore_immediato — i registri di segmento accettano solo un registro generale come sorgente. La sequenza obbligatoria è sempre: MOV AX, data seguito da MOV DS, AX.Struttura di un programma Assembly
Direttive Standard — 4 segmenti
Le direttive standard prevedono la dichiarazione esplicita di fino a quattro segmenti distinti. È il modello più dettagliato e più vicino al funzionamento reale dell’8086.
; ── TEMPLATE COMPLETO .EXE CON DIRETTIVE STANDARD ──────────────────────
data SEGMENT ; inizio Data Segment
variabile DB 42d ; variabile byte inizializzata
messaggio DB 'Ciao!', '$' ; stringa terminata da $
risultato DB ? ; variabile byte non inizializzata
COSTANTE EQU 10h ; costante simbolica
data ENDS ; fine Data Segment
stack SEGMENT STACK ; inizio Stack Segment
DB 100h DUP(?) ; riserva 256 byte per lo stack
stack ENDS
code SEGMENT ; inizio Code Segment
ASSUME CS:code, DS:data, SS:stack
start: ; label di inizio programma
MOV AX, data ; carica indirizzo Data Segment in AX
MOV DS, AX ; inizializza DS (obbligatorio)
; ── codice del programma ────────────────────────────────────────────
MOV AL, variabile
ADD AL, COSTANTE
MOV risultato, AL
; ── fine programma ──────────────────────────────────────────────────
MOV AH, 4Ch ; INT 21h servizio 4Ch: termina programma
INT 21h
code ENDS
END start ; fine file — label di inizio = startDirettive Semplificate — .model
Le direttive semplificate sostituiscono le dichiarazioni esplicite dei segmenti con macro predefinite. Il codice risulta più compatto — l’assembler gestisce automaticamente i registri di segmento.
| Modello | Segmenti codice | Segmenti dati | Uso tipico |
|---|---|---|---|
tiny | 1 (condiviso) | 1 (condiviso) | File .COM — tutto in un segmento |
small | 1 | 1 | Programmi piccoli — il più comune in corso |
compact | 1 | multipli | Dati grandi, codice piccolo |
medium | multipli | 1 | Codice grande, dati piccoli |
large | multipli | multipli | Applicazioni grandi e complesse |
Il Data Segment — variabili e costanti
In Assembly ogni variabile deve essere dichiarata esplicitamente nel Data Segment prima che il codice possa usarla. La dichiarazione specifica nome, dimensione e valore iniziale (oppure ? se non inizializzata).
Direttive di definizione dati
8 bit
0–255
16 bit
0–65535
32 bit
64 bit
BCD packed
; ── esempi di dichiarazione variabili ────────────────────────────────────
; variabili numeriche
a DB 67d ; 1 byte — valore 67 decimale
b DB 53o ; 1 byte — valore 53 ottale = 43 decimale
n1 DW 345o ; 2 byte — valore 345 ottale = 229 decimale
n2 DW 76h ; 2 byte — valore 76 esadecimale = 118 decimale
; variabili non inizializzate
x DB ? ; 1 byte — valore da definire a runtime
y DB ?
ris DB ?
somma DW ? ; 2 byte — non inizializzato
differenza DW ?
; costanti — dichiarate con EQU (non occupano memoria)
C EQU 4h ; costante = 4 esadecimale
D EQU 1001b ; costante = 1001 binario = 9 decimale
; array e stringhe
voti DB 28d, 30d, 25d, 27d ; array di 4 byte
buffer DB 10 DUP(?) ; 10 byte non inizializzati (buffer)
msg DB 'Risultato: ', '$' ; stringa terminata da $ per INT 21h
carattere DB 'A' ; singolo carattere ASCII67d o 67 → decimale43h o 0x43 → esadecimale53o → ottale1001b → binarioEQU è una costante simbolica — l’assembler sostituisce il nome con il valore a tempo di assemblaggio. Non occupa memoria. DB/DW è una variabile — occupa locazioni reali nel Data Segment.Il teorema di Böhm-Jacopini — le tre strutture
Il Teorema di Böhm-Jacopini dimostra che qualsiasi algoritmo computabile può essere espresso usando solo tre strutture di controllo fondamentali. Anche in Assembly — dove tutto è esplicito — si implementano le stesse strutture, ma con istruzioni di confronto e salto.
Esercizio 1 — Sequenza
a = 67d, b = 53o e le costanti C = 4h, D = 1001b, calcolare:x = a + Dy = b + Cris = x - y
; ── ESERCIZIO 1: SEQUENZA ─────────────────────────────────────────────────
data SEGMENT
a DB 67d ; a = 67 decimale
b DB 53o ; b = 53 ottale = 43 decimale
C EQU 4h ; costante C = 4 esadecimale (non occupa memoria)
D EQU 1001b ; costante D = 1001 binario = 9 decimale
x DB ? ; x = a + D → risultato intermediario
y DB ? ; y = b + C → risultato intermediario
ris DB ? ; ris = x - y → risultato finale
data ENDS
stack SEGMENT STACK
DB 100h DUP(?)
stack ENDS
code SEGMENT
ASSUME CS:code, DS:data, SS:stack
start:
MOV AX, data ; inizializza DS
MOV DS, AX
; ── calcolo x = a + D ────────────────────────────────────────────────
MOV AL, a ; AL ← a = 67d
ADD AL, D ; AL ← 67 + 9 = 76d
MOV x, AL ; x ← 76d
; ── calcolo y = b + C ────────────────────────────────────────────────
MOV AL, b ; AL ← b = 43d (53 ottale)
ADD AL, C ; AL ← 43 + 4 = 47d
MOV y, AL ; y ← 47d
; ── calcolo ris = x - y ──────────────────────────────────────────────
MOV AL, x ; AL ← x = 76d
SUB AL, y ; AL ← 76 - 47 = 29d
MOV ris, AL ; ris ← 29d = 1Dh
MOV AH, 4Ch ; termina programma
INT 21h
code ENDS
END startEsercizio 2 — Selezione (if-else)
n1 = 345o e n2 = 76h: se n1 > n2 calcola la somma e memorizzala in somma, altrimenti calcola la differenza e memorizzala in differenza.n1 = 345o → 3×64 + 4×8 + 5×1 = 192+32+5 = 229dn2 = 76h → 7×16 + 6×1 = 112+6 = 118d; ── ESERCIZIO 2: SELEZIONE ────────────────────────────────────────────────
data SEGMENT
n1 DW 345o ; 229 decimale — DW perché potrebbe superare 255
n2 DW 76h ; 118 decimale
somma DW ?
differenza DW ?
data ENDS
stack SEGMENT STACK
DB 100h DUP(?)
stack ENDS
code SEGMENT
ASSUME CS:code, DS:data, SS:stack
start:
MOV AX, data
MOV DS, AX
MOV AX, n1 ; AX ← n1 = 229d
CMP AX, n2 ; confronta AX con n2 — imposta i flag
JG ramo_maggiore ; se n1 > n2 salta a ramo_maggiore
; ── ramo else: n1 ≤ n2 → calcola differenza ─────────────────────────
SUB AX, n2 ; AX ← n1 - n2
MOV differenza, AX
JMP fine ; salta oltre il ramo if (evita di eseguirlo)
ramo_maggiore: ; ── ramo if: n1 > n2 → calcola somma ──────────
ADD AX, n2 ; AX ← n1 + n2 = 229 + 118 = 347d
MOV somma, AX
fine:
MOV AH, 4Ch
INT 21h
code ENDS
END startEsercizio 3 — Ciclo FOR (fattoriale di 5)
; ── ESERCIZIO 3: CICLO FOR — fattoriale di 5 ─────────────────────────────
; Equivalente C: for(int i=5; i>=1; i--) { ris *= i; }
data SEGMENT
numero DB 5d ; valore di partenza del contatore
risultato DW 1d ; accumulatore inizializzato a 1
data ENDS
stack SEGMENT STACK
DB 100h DUP(?)
stack ENDS
code SEGMENT
ASSUME CS:code, DS:data, SS:stack
start:
MOV AX, data
MOV DS, AX
MOV AX, risultato ; AX = 1 (accumulatore)
MOV CL, numero ; CL = 5 (contatore)
ciclo_for: ; ── inizio corpo del ciclo ─────────────────────
MUL CL ; AX ← AX × CL (5,4,3,2,1)
DEC CL ; CL-- (contatore decrementa)
CMP CL, 1d ; CL == 1? (condizione di uscita)
JGE ciclo_for ; se CL >= 1 → continua il ciclo
MOV risultato, AX ; salva 120d = 78h in risultato
MOV AH, 4Ch
INT 21h
code ENDS
END start| Iterazione | CL prima | AX = AX × CL | CL dopo DEC |
|---|---|---|---|
| 1 | 5 | 1 × 5 = 5 | 4 |
| 2 | 4 | 5 × 4 = 20 | 3 |
| 3 | 3 | 20 × 3 = 60 | 2 |
| 4 | 2 | 60 × 2 = 120 | 1 |
| Fine | 1 | CL = 1 → JGE non salta | — |
Esercizio 4 — Ciclo WHILE (fattoriale di 5)
; ── ESERCIZIO 4: CICLO WHILE — fattoriale di 5 ───────────────────────────
; Equivalente C: while(CL > 1) { ris *= CL; CL--; }
data SEGMENT
numero DB 5d
risultato DW 1d
data ENDS
stack SEGMENT STACK
DB 100h DUP(?)
stack ENDS
code SEGMENT
ASSUME CS:code, DS:data, SS:stack
start:
MOV AX, data
MOV DS, AX
MOV AX, risultato ; AX = 1
MOV CL, numero ; CL = 5
controllo_while: ; ── test condizione PRIMA del corpo ────────────
CMP CL, 1d ; CL == 1? (condizione: CL > 1 per continuare)
JLE fine_while ; se CL ≤ 1 → esci dal ciclo
; ── corpo del ciclo ──────────────────────────────────────────────────
MUL CL ; AX ← AX × CL
DEC CL ; CL--
JMP controllo_while ; torna al controllo
fine_while:
MOV risultato, AX ; AX = 120d = 78h
MOV AH, 4Ch
INT 21h
code ENDS
END startcorpo;
DEC CL;
CMP CL, 1;
JGE inizio
CMP CL, 1;
JLE fine;
corpo;
DEC CL;
JMP controllo
Riepilogo
- EMU8086 emula l’8086 permettendo di osservare registri, memoria e codice macchina istruzione per istruzione — strumento fondamentale per il debug e la comprensione del ciclo fetch-decode-execute
- Il formato .COM usa un segmento unico da 64 KB (codice da
ORG 100h), il formato .EXE usa segmenti separati con DS da inizializzare esplicitamente - DS non può essere caricato direttamente — si passa sempre per AX:
MOV AX, data→MOV DS, AX - Ogni programma .EXE termina con
MOV AH, 4Ch/INT 21hper restituire il controllo al SO - Le variabili si dichiarano nel Data Segment con DB (1B), DW (2B), DD (4B), DQ (8B) — le costanti con EQU (non occupano memoria)
- Le stringhe per INT 21h devono terminare con il carattere
$ - La sequenza è l’esecuzione lineare di istruzioni — la struttura più semplice
- La selezione si implementa con CMP + salto condizionato (JG, JL, JE…) + JMP per saltare il ramo alternativo
- Il ciclo FOR in Assembly: corpo → DEC → CMP → salto condizionato — la condizione è in fondo (do-while)
- Il ciclo WHILE in Assembly: CMP → salto uscita → corpo → DEC → JMP indietro — la condizione è in testa