ISA 8086 - Istruzioni e Interrupt | Sistemi e Reti - Modulo 2 - Lezione 07
Sistemi e Reti · Anno 3 · Modulo 2 · Lezione 07
✍ Autore: profgiagnotti · Materia: Sistemi e Reti

ISA 8086 — Set di Istruzioni e Interrupt

Il vocabolario della CPU: dal MOV ai flag, dalle maschere di bit ai salti condizionati, fino a INT 21h per gestire input/output in Assembly 8086.

📘 Cheatsheet Assembly 8086
// OBIETTIVI DI APPRENDIMENTO
✓Conoscere la classificazione dell'ISA 8086 e le principali categorie di istruzioni: trasferimento, aritmetica, logica/shift e controllo flusso.
✓Usare correttamente MOV, PUSH/POP, XCHG, LEA e comprendere il vincolo dei due operandi in memoria e la gestione dei flag.
✓Padroneggiare le istruzioni aritmetiche ADD, SUB, MUL, DIV, CMP, il complemento a 2 e il funzionamento di ZF, SF, CF, OF, PF.
✓Implementare maschere di bit con AND/OR/XOR/NOT, ottimizzare con SHL/SHR/ROL/ROR e costruire if/else e cicli con CMP, Jcc e LOOP.
✓Capire il meccanismo degli interrupt: IVT, flusso INT/IRET, uso di INT 21h per I/O da tastiera/video e terminazione programma.

1. L'ISA — Instruction Set Architecture

📌 Definizione da ricordare

L'ISA è il contratto tra software e hardware: definisce istruzioni, formati, modi di indirizzamento e comportamento dei flag. L'8086 è il vocabolario base di tutti gli x86.

L'ISA (Instruction Set Architecture) è l'insieme completo di istruzioni che un processore è in grado di eseguire — è il "vocabolario" della CPU. L'ISA dell'8086 definisce le istruzioni, i formati, i modi di indirizzamento e il comportamento dei flag: è il contratto tra il software e l'hardware.

01 · Trasferimento

MOV PUSH POP

Movimentazione dati tra registri, memoria e stack. XCHG, LEA per indirizzi.

02 · Aritmetica

ADD SUB MUL DIV

Calcoli interi, complemento a 2, prodotto doppio, divisione con resto.

03 · Logica / Shift

AND OR SHL SHR

Maschere di bit, ottimizzazione ×/÷ potenze di 2, rotazioni.

TRASFERIMENTO MOV PUSH POP XCHG LEA ARITMETICA ADD SUB MUL DIV INC DEC CMP NEG LOGICA / SHIFT AND OR XOR NOT SHL SHR ROL ROR CONTROLLO FLUSSO JMP Jcc LOOP CALL RET INT

2. I flag — il registro di stato FLAGS

Molte istruzioni non restituiscono il risultato solo in un registro — modificano anche i flag nel registro FLAGS. I flag sono bit singoli che memorizzano informazioni sul risultato dell'ultima operazione e guidano i salti condizionati.

FlagNomeSi attiva quando...Usato da
ZFZero FlagIl risultato è zero (o i due operandi di CMP sono uguali)JE, JNE, LOOPE, LOOPNE
SFSign FlagBit più significativo =1 (risultato negativo in complemento a 2)JG, JL, JGE, JLE
CFCarry FlagRiporto/prestito fuori dal MSB (overflow senza segno)JA, JB, ADC, SBB
OFOverflow FlagRisultato non entra nel tipo con segnoJO, JNO
PFParity FlagN° bit a 1 pari nel risultatoControllo parità seriale
💬 Tip del docente

Per l'interrogazione ricorda: MOV non tocca mai i flag. ADD/SUB/CMP sì, INC/DEC no sul CF. Se vedi ZF=1 dopo CMP sai già che i due valori sono uguali.

3. Istruzioni di trasferimento dati

MOV — copia di dati

MOV è l'istruzione più usata dell'ISA — copia il valore del secondo operando nel primo. Non è uno spostamento: la sorgente rimane invariata. Non modifica i flag.

Assembly 8086 · MOV
; MOV destinazione, sorgente MOV AL, 34d ; AL ← 34 decimale (0x22) — immediato MOV AX, BX ; AX ← BX — registro a registro MOV AX, [6Ah] ; AX ← Mem[DS:6Ah] — da memoria MOV [0200h], BX ; Mem[DS:0200h] ← BX — in memoria
⚠️ Errore comune — vincolo fondamentale

Non è mai possibile avere entrambi gli operandi in memoria nella stessa MOV. Per copiare da memoria a memoria servono due istruzioni: prima carica in un registro, poi scrivi.

PUSH e POP — gestione dello stack

PUSH inserisce un valore a 16 bit in cima allo stack decrementando SP di 2, POP preleva il valore incrementando SP di 2. Lo stack cresce verso il basso.

Assembly 8086 · Stack LIFO
PUSH AX ; SP ← SP - 2 · Mem[SS:SP] ← AX PUSH BX ; salva BX sopra AX POP BX ; BX ← Mem[SS:SP] · SP ← SP + 2 (LIFO!) POP AX ; AX ripristinato

XCHG e LEA

Assembly 8086 · XCHG / LEA
XCHG AX, BX ; scambia AX e BX senza registro temporaneo LEA SI, [array] ; SI ← indirizzo di 'array', NON il suo valore LEA DI, 04h[BX] ; DI ← BX + 4 (indirizzo effettivo calcolato)
🎯 Esempio in classe — LEA vs MOV

MOV SI, [array] carica il dato contenuto in array. LEA SI, [array] carica l'indirizzo di array — equivale a &array in C. Indispensabile per passare puntatori a stringhe o buffer alle routine INT 21h.

4. Istruzioni aritmetiche

ADD e SUB — con complemento a 2

Assembly 8086 · ADD / SUB
MOV AL, 34d ; AL = 0x22 ADD AL, 5d ; AL = AL + 5 = 39d = 0x27 SUB AL, 10d ; AL = 39 - 10 = 29d = 0x1D
📌 Definizione da ricordare

Se il risultato di SUB è negativo, la CPU lo rappresenta in complemento a 2. Su 8 bit: -21d → 21d=00010101 → NOT=11101010 → +1 = 11101011 = EBh, SF=1.

Assembly 8086 · Complemento a 2
SUB AL, 50d ; AL era 29d → 29 - 50 = -21d ; -21 in complemento a 2 su 8 bit: ; 21d = 0001 0101 ; NOT = 1110 1010 (complemento a 1) ; +1 = 1110 1011 (complemento a 2) = EBh ; AL conterrà EBh — SF=1 (bit7=1 → numero negativo)

ADC e SBB — con riporto e prestito

Per somme su operandi più grandi del registro (es. 32 bit su CPU a 16 bit), si usano ADC e SBB che includono CF dell'operazione precedente.

Assembly 8086 · ADC 32 bit
; somma a 32 bit: (DX:AX) + (CX:BX) → risultato in (DX:AX) ADD AX, BX ; somma i 16 bit bassi — può generare carry ADC DX, CX ; somma i 16 bit alti + eventuale carry dal passo precedente

MUL — moltiplicazione

MUL moltiplica sempre usando AL o AX come operando implicito. Il risultato è sempre il doppio della dimensione — per evitare overflow.

Operando 8 bit

AL × op8 → AX

MOV AL,50 · MOV BL,10 · MUL BL → AX=500d=01F4h

Operando 16 bit

AX × op16 → DX:AX

MOV AX,1000 · MOV BX,500 · MUL BX → DX:AX=500000d=0x7A120 → DX=0007h AX=A120h

Assembly 8086 · MUL
; 8 bit MOV AL, 50d ; AL = moltiplicando MOV BL, 10d ; BL = moltiplicatore MUL BL ; AX ← AL × BL → 500d = 01F4h ; 16 bit MOV AX, 1000d MOV BX, 500d MUL BX ; DX:AX ← AX × BX = 500000d = 7A120h

DIV — divisione

Divisore 8 bit

AX ÷ op8 → AL quoziente · AH resto

AX=100, BL=30 → AL=3, AH=10

Divisore 16 bit

DX:AX ÷ op16 → AX quoziente · DX resto

DX:AX=100000, BX=100 → AX=1000, DX=0

Assembly 8086 · DIV
MOV AX, 100d ; dividendo in AX MOV BL, 30d ; divisore DIV BL ; AL=3 (quoziente) · AH=10 (resto) ; 16 bit: 100000 ÷ 100 MOV DX, 1h ; parte alta MOV AX, 86A0h ; parte bassa (DX:AX=100000d) MOV BX, 100d DIV BX ; AX=1000d=03E8h · DX=0

INC, DEC, NEG, CMP

Assembly 8086 · INC DEC NEG CMP
INC AL ; AL = AL + 1 (non modifica CF — utile nei cicli) DEC CX ; CX = CX - 1 NEG AL ; AL = -AL (complemento a 2 di AL) ; CMP sottrae senza salvare — aggiorna solo i flag MOV AL, 50d MOV BL, 10d CMP BL, AL ; BL - AL = 10 - 50 = -40 → CF=1, SF=1, ZF=0
💬 Tip del docente

CMP op1,op2 esegue internamente op1-op2 ma scarta il risultato — aggiorna solo ZF, SF, CF, OF. Se op1=op2 ZF=1. Se op1<op2 CF=1,SF=1. Se op1>op2 tutti 0. Sempre seguita da Jcc.

5. Istruzioni logiche e di shift

Operazioni bitwise — AND, OR, XOR, NOT

Operano bit per bit. Fondamentali per flag di stato, maschere, azzeramento veloce.

AND

Azzerare bit (masking)

MOV AL,11001010b · AND AL,00001111b → 00001010b. Tronca nibble alto.

OR

Impostare bit

MOV AL,10110000b · OR AL,00000111b → 10110111b.

Assembly 8086 · AND OR XOR NOT
MOV AL, 0b11001010 ; AL = 0xCA AND AL, 0b00001111 ; maschera nibble basso → 0x0A MOV AL, 0b10110000 OR AL, 0b00000111 ; forza 3 bit bassi → 0xB7 XOR AX, AX ; AX=0 (idioma più veloce di MOV AX,0) XOR AL, 0FFh ; inverte tutti i bit (comp. a 1) MOV AL, 0b10110001 NOT AL ; → 0b01001110
🎯 Esempio in classe — maschere di rete

In Sistemi e Reti usiamo AND per estrarre la rete da IP: 192.168.1.10 AND 255.255.255.0 → 192.168.1.0. Stesso meccanismo in Assembly per isolare bit di stato.

SHL, SHR, ROL, ROR

Shift sposta e perde bit (o in CF). Rotazione fa rientrare il bit uscente dall'altro lato.

SHL / SHR — moltiplica e divide ×2ⁿ 00000101 (5) SHL 1 → 00001010 (10) 00101000 (40) SHR 1 → 00010100 (20) ROL / ROR — rotazione circolare 10110001 ROL 1 → 01100011 10110001 ROR 1 → 11011000 bit uscente rientra dal lato opposto
Assembly 8086 · Shift/Rotazione
MOV AL, 5d ; 00000101 SHL AL, 1 ; → 00001010 =10d (×2) SHL AL, 2 ; → 00101000 =40d (×4) — 1 ciclo vs MUL MOV AL, 10110001b ROL AL, 1 ; → 01100011b (bit7 rientra bit0) ROR AL, 1 ; → 11011000b (bit0 rientra bit7)
💬 Tip del docente

SHL di N = ×2ⁿ in 1 ciclo vs molti cicli di MUL. Nei loop ad alte prestazioni usa shift per potenze di 2. SHR per ÷2ⁿ intera.

6. Controllo del flusso — salti e cicli

JMP — salto incondizionato

Assembly 8086 · JMP
MOV AL, 100d MOV BL, 30d JMP fine ; salta direttamente a fine MOV AL, 35d ; NON eseguita MOV BL, 40d ; NON eseguita fine: MOV AL, 10d ; riprende qui

CMP + salti condizionati — if/else

Coppia CMP + Jcc è il mattone di ogni if/else in Assembly.

Assembly 8086 · If/Else con CMP/JG
; if (AL > BL) ramo_vero else ramo_falso MOV AL, 50d MOV BL, 30d CMP AL, BL ; imposta flag JG ramo_vero ; salta se AL > BL (con segno) ; --- ramo_falso --- MOV CX, 0d ; AL ≤ BL JMP fine_if ramo_vero: MOV CX, 1d ; AL > BL fine_if:
IstruzioneCondizioneFlagInterpretazione
JE / JZop1 = op2ZF=1Uguale / Zero
JNE / JNZop1 ≠ op2ZF=0Diverso / Non zero
JGop1 > op2ZF=0 e SF=OFMaggiore con segno
JAop1 > op2CF=0 e ZF=0Maggiore senza segno
JLop1 < op2SF≠OFMinore con segno
JBop1 < op2CF=1Minore senza segno
JGE / JAEop1 ≥ op2SF=OF / CF=0Maggiore o uguale
JLE / JBEop1 ≤ op2ZF=1 o SF≠OFMinore o uguale
⚠️ Con segno vs senza segno

Stessi bit, significato diverso: AL=10 (0x0A), BL=-30 (0xE2 =226 senza segno). CMP AL,BL → con segno (JG) AL>BL → salta. Senza segno (JA) AL

Assembly 8086 · Con segno vs senza segno
MOV AL, 10d ; 0x0A MOV BL, -30d ; 0xE2 = 226 unsigned / -30 signed CMP AL, BL ; Con segno (JG/JL): 10 > -30 → JG salta ✓ ; Senza segno (JA/JB): 10 < 226 → JA non salta

LOOP — cicli con contatore

LOOP usa CX come contatore implicito: decrementa CX e salta se CX≠0. Equivale a for con CX iterazioni.

Assembly 8086 · LOOP for somma 1..5
; somma 1+2+3+4+5 MOV CX, 5d ; contatore MOV AX, 0d ; accumulatore ciclo: ADD AX, CX ; AX = AX + CX LOOP ciclo ; CX-- · se CX≠0 → salta ; AX=15d · CX=0
LOOP

Salta se CX≠0

Dopo decremento automatico di CX.

LOOPE

CX≠0 e ZF=1

Preceduta da CMP, utile per ricerca.

LOOPNE

CX≠0 e ZF=0

Continua fino a trovare o esaurire CX.

CALL e RET — subroutine

Assembly 8086 · CALL RET
CALL mia_funzione ; salva IP nello stack · salta ; ← riprende qui dopo RET MOV BX, AX ; usa valore restituito mia_funzione: MOV AX, 42d ; convenzione: ritorno in AX RET ; recupera IP dallo stack

7. Interrupt e I/O

📌 Definizione — cos'è un interrupt

Un interrupt è un evento che sospende il ciclo fetch-decode-execute: la CPU salva IP e FLAGS nello stack ed esegue l'Interrupt Handler (ISR). IRET ripristina il contesto.

I programmi Assembly devono interagire con tastiera, schermo e altri dispositivi. In x86 questo avviene attraverso gli interrupt software.

01 · INT N Programma esegue INT → 02 · Salva stato FLAGS + IP nello stack → 03 · IVT [N×4] Consulta 0000:0000h → 04 · Handler Esegue servizio I/O → 05 · IRET Ripristina e torna IVT = tabella di 256 entry × 4 byte (IP + CS) all'indirizzo 0000:0000h. Handler N a offset N×4.
01 · Richiesta

INT N (0–255)

Numero interrupt identifica servizio.

02 · Contesto

Salvataggio FLAGS e IP

Disabilita interrupt, salva stato su stack SS:SP.

INT 21h — i servizi DOS

Interrupt più usato in DOS: INT 21h. Servizio selezionato caricando codice in AH.

AHServizioInputOutput
01hLeggi carattere da tastiera con echo—AL = ASCII tasto
02hScrivi carattere a videoDL = ASCII—
09hStampa stringa a videoDS:DX = indirizzo stringa terminata da $—
0AhLeggi stringa con bufferDS:DX = indirizzo bufferBuffer riempito
4ChTermina programmaAL = codice uscita—
Assembly 8086 · INT 21h Leggi e stampa carattere
; esempio completo: leggi un carattere e stampalo MOV AH, 01h ; servizio: leggi carattere da tastiera INT 21h ; AL ← ASCII del tasto premuto MOV DL, AL ; preparo carattere da stampare MOV AH, 02h ; servizio: scrivi carattere a video INT 21h ; stampa DL MOV AH, 4Ch ; termina MOV AL, 0 ; exit code 0 OK INT 21h
Assembly 8086 · Stampa stringa $
; stampa una stringa — deve terminare con '$' msg DB 'Ciao, mondo!', '$' MOV AH, 09h ; stampa stringa LEA DX, msg ; DX ← indirizzo di msg INT 21h ; stampa fino a '$'
💬 Tip del docente

In Emu8086 usa LEA DX,msg prima di INT 21h/09h. Ricorda il '$' finale altrimenti stampa spazzatura. Per input sicuro usa AH=0Ah con buffer predefinito.

CategoriaIstruzioni principaliNota chiave
TrasferimentoMOV PUSH POP XCHG LEAMOV non modifica flag · LEA carica indirizzi non valori
AritmeticaADD ADC SUB SBB MUL DIV INC DEC NEG CMPMUL: AL×op→AX · AX×op→DX:AX · CMP scarta risultato
LogicaAND OR XOR NOTXOR reg,reg azzera · AND per maschere
Shift/RotazioneSHL SHR ROL RORSHL/SHR: ×/÷ per potenze di 2 in 1 ciclo
Salto incond.JMP CALL RETCALL salva IP su stack · RET lo recupera
Salto condiz.JE JNE JG JA JL JB JGE JLE…J* con segno (JG/JL) · J* senza segno (JA/JB)
CicliLOOP LOOPE LOOPNEUsano CX come contatore implicito — CX-- poi controlla
InterruptINT N IRETINT 21h + AH = servizio DOS per I/O

9. Verifica e attività in Emu8086

🔬 Attività pratica

Apri Emu8086 e realizza i seguenti mini-programmi. Usa la cheatsheet Assembly 8086 come riferimento.

  1. Scrivi un programma che legge un carattere con INT 21h/01h e, se è una lettera minuscola, la converte in maiuscola usando AND 11011111b e la stampa.
  2. Implementa somma 1..10 con LOOP: verifica che AX =55d (0x37). Cosa succede se dimentichi MOV CX,10?
  3. Usa SHL per moltiplicare AL=7 per 8 senza MUL. Confronta i cicli con emulatore: quanti cicli risparmi?
  4. Gestisci l'errore DIV per zero: cosa mostra Emu8086? Come proteggeresti il codice con CMP e JE prima di DIV?
  5. Esercizio INT 21h/09h: stampa due stringhe diverse a seconda che il carattere letto sia 's' o 'n' (simula conferma).
✅ Soluzione ragionata — conversione minuscola/maiuscola

La differenza ASCII tra 'a' (0x61=01100001) e 'A' (0x41=01000001) è il bit 5. AND con 11011111b (0xDF) azzera quel bit → minuscola→maiuscola. Per controllo intervallo: CMP AL,'a' / JB non_minuscola / CMP AL,'z' / JA non_minuscola. Questo mostra AND come maschera.

📚 Prossimo passo — Ambiente di simulazione Emu8086

Ora che conosci l'ISA, vedremo come strutturare un programma completo in Emu8086, usare segmenti, direttive e debugger per testare i tuoi primi programmi. Tieni aperta la cheatsheet Assembly.