1. Dispense del corso di
Architettura dei Calcolatori
Intel 8086/8 – ISA e Assembly
2. a.a. 2007/2008
Architettura dei calcolatori
Intel 8086
Bus indirizzi (20bit)
AX
BX
CX
DX
SP
BP Bus dati
(16bit)
DI CS
SI DS
ES
SS
IP
BUS
Internal
cntr.
Temporary regs.
Instruction queue
EU
ALU cntr.
FLAGS
BIU
EU
3. a.a. 2007/2008
Architettura dei calcolatori
I registri della CPU 8086
• Il set di registri è la parte più importante di ciò che è visibile dal programmatore o
al compilatore
• Registri sono divisi in:
– General Purpose Registers,
– Segment Registers,
– Miscellaneous Registers
Registers.
• I General Purpose Registers hanno in realtà uno scopo ben preciso insito nel
loro nome (non ortogonali) , anche se molte istruzioni consentono di utilizzare i
registri generici indipendentemente dal loro scopo primario.
• I registri sono AX BX CX DX SI DI BP SP
AX, BX, CX, DX, SI, DI, BP, SP.
• Questi sono registri a 16 bit e per i primi 4 è possibile accedere direttamente agli
8 bit più significativi (parte alta/high) o agli 8 bit meno significativi (parte
bassa/low) specificando H o L invece che X. Cioè, per esempio, CL è il registro a
8 bit corrispondente alla parte bassa di CX, mentre AH è la parte alta di AX.
4. a.a. 2007/2008
Architettura dei calcolatori
I registri generici
• AX è l’accumulatore: serve per numerose operazioni matematiche, o di I/O o per speciali
trasferimenti di dati.
• BX è il registro base: serve per contenere l’indirizzo di partenza durante gli indirizzamenti in
memoria.
• CX è il registro di conteggio: serve per effettuare conteggi durante cicli o ripetizioni
ripetizioni.
• DX è il registro dati: per contenere parte di dati eccedenti durate le operazioni aritmetiche(in
coppia con AX) e per g indirizzi delle istruzioni di I/O.
) gli
• SI e DI sono registri indice utilizzati principalmente durante le operazioni con stringhe di
byte. Tipicamente SI punta alla sorgente, mentre DI punta alla destinazione.
• BP è il puntatore base e, in modo molto simile a BX, serve come indirizzo di
partenza(principalmente entro lo stack), tipicamente durante l’accesso a parametri e
variabili di funzioni.
• SP è il puntatore allo stack: l’8086 ha istruzioni per la gestione di questa struttura dati
direttamente nella sua architettura e questo registro viene implicitamente referenziato da
tutte queste istruzioni.
istruzioni
5. a.a. 2007/2008
Architettura dei calcolatori
I registri di segmento
• Senza entrare nel dettaglio del funzionamento dei segmenti, tali registri sono stati definiti
perchè l’Intel si trovò di fronte al problema di indirizzare 1MB di memoria e che per motivi di
progetto ed economici decise di non utilizzare registri a 20bit, ma di combinare
opportunamente due registri a 16bit
16bit.
• Esistono quindi 4 registri di segmento che hanno la funzione di suddividere la
memoria in parti relative ai dati in esse contenuti:
– CS è l’indirizzo del segmento codice, cioè l’area di memoria da cui vengono
lette le istruzioni da eseguire.
– DS è l’indirizzo del segmento dati, cioè l’area di memoria che contiene le
variabili o le costanti necessarie al programma.
– ES è l’indirizzo del segmento ausiliario che consente di disporre rapidamente
di ulteriore spazio per i dati senza dovere continuamente modificare DS.
– SS è l’indirizzo del segmento di stack.
• L’utilizzo dei segmenti consente una notevole flessibilità, ma complica
notevolmente la progettazione del software in particolare per le strutture dati di
software,
dimensioni superiori ai 64KB.
6. a.a. 2007/2008
Architettura dei calcolatori
Registri speciali
• Esistono due ulteriori registri speciali che non vengono modificati direttamente
dal programmatore, ma sono fondamentali per l’esecuzione del software:
– IP è l’instruction pointer, cioè l’indirizzo, all’interno del code segment
dal quale prelevare la prossima istruzione.Specifica l’offset della
successiva istruzione da eseguire in riferimento al segmento codice
g g
corrente.
– FLAG è un registro a 16 bit nel quale ogni bit (9 utilizzati nel 8086) ha
un significato speciale che indica la modalità di funzionamento del
software, lo stato del sistema o il risultato dell’istruzione precedente.
• Le istruzioni possono fare riferimento a tutti i registri generali e di segmento per
leggerne o scriverne il valore, con l’eccezione di CS che può solo essere letto.
• Non è possibile fare riferimento a IP o a FLAG, perché questi sono
implicitamente o esplicitamente modificati da istruzioni apposite.
• CS:IP e’ il corrispondente del Program Counter nella micro architettura
7. a.a. 2007/2008
Architettura dei calcolatori
Il registro FLAG
15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
OF DF IF TF SF ZF AF PF CF
• Ecco una breve descrizione del significato dei singoli bit:
Flag di Stato:
– Overflow(OF): Indica che operazione ha riportato un risultato troppo grande
– Sign(SF): Viene posto a 1 se il risultato di una operazione è negativo
– Z (ZF) Vi
Zero(ZF): Viene messo a 1 se il risultato di una operazione è 0
i lt t i
– Auxiliary Carry(AF): Indica un riporto o un prestito tra la parte bassa e quella alta di un
numero. Viene usato dalle istruzioni aritmetico decimale.
– Parity Flag(PF): Posto a 1 quando c’è un numero pari di bit a 1 nel risultato
cè
dell’operazione. Utilizzato dai programmi di comunicazione.
– Carry Flag(CF): Indica un riporto o un prestito nella parte alta dell’ultimo risultato.
Serve per realizzare istruzioni multi word.
Flag di Controllo:
– Direction(DF): Indica se decrementare o incrementare per le istruzioni con le stringhe.
Indica se la stringa viene letta/scritta a p
g partire dall’elemento con indirizzo piu’
p
alto/basso
– Interrupt Enable(IF): Indica se le interruzioni mascherabili sono abilitate
– Trap(TF): Questo flag è usato dai debugger per eseguire i p g
p( ) g gg p g programmi un p passo alla
volta. Genera un INT 3 dopo ogni istruzione
8. a.a. 2007/2008
Architettura dei calcolatori
Assemblatore Intel
• Il codice macchina è una sequenza numerica che codifica le istruzioni e gli operandi. Ad
esempio, il codice operativo 8A 49 E4 indica di copiare il byte contenuto all’indirizzo di
memoria dato da BX+DI-28 nel registro CL.
• Non
N è molto comodo programmare calcolando il codice macchina, per questo motivo si
lt d lld di hi t ti i
utilizza un programma che traduce le istruzioni da una forma testuale più comprensibile al
programmatore nel codice macchina.
• L’istruzione precedente p allora essere scritta come:
p può
mov cl,[bx+di-28]
• Non esiste purtroppo un accordo ufficiale sulla sintassi che deve essere rispettata da un
assemblatore ed esistono diverse varianti per lo stesso codice operativo.
– Ad esempio l’istruzione precedente, con il Microsoft Macro
Assembler (MASM), può essere scritta come mov cl,[bx+di]-28
o mov cl,[bx][di][-28] o mov cl,[di][-28][bx], ecc...
• Un altro pacchetto disponibile e’ il “flat assembler” (FASM) un assemblatore che può
essere utilizzato gratuitamente e del quale sono disponibili i sorgenti in rete.
• Per i dettagli sulla sintassi di questo assemblatore si rimanda alla documentazione Solo per
chiarezza, per coloro che hanno utilizzato altri assemblatori, notiamo che la sintassi degli
indirizzi è molto più rigida: quando si specifica un operando in memoria questo deve essere
compreso tra parentesi quadre e all’interno delle parentesi possono comparire registri,
etichette e valori immediati separati da “più”. Inoltre nella dichiarazione di dati la direttiva
dup viene sostituita da times che ha una sintassi leggermente diversa.
9. a.a. 2007/2008
Architettura dei calcolatori
Linguaggio macchina ed assembler
• Linguaggio macchina è binario
• Linguaggio assembler è in forma simbolica;
• Il formato di una istruzione in assembler è il seguente:
Etichetta: Mnemonico Operando1, Operando2; Commento
• Etichetta
– è un identificatore (stringa) cui è assegnato l’indirizzo del primo byte
dell’istruzione alla quale si riferisce
– Può servire come nome simbolico cui riferirsi nei salti condizionati e
incondizionati
• Mnemonico
– indica l’operazione vera e propria
• es: operazione di somma => ADD
i >
• Operando
– la presenza dipende dall’istruzione
– possiamo avere istruzioni con 1 2 o nessun operando
1,
• Commento
– Se non presente il punto e virgola può essere omesso
10. a.a. 2007/2008
Architettura dei calcolatori
Regole di Sintassi - Costanti numeriche
• Un numero con suffisso che indica la base:
– B o b (binario),
– D o d (decimale)
(decimale),
– O o o (ottale),
– H o h (esadecimale).
• Per default la base è d i l
P d f lt l b decimale
• In caso di base esadecimale la prima cifra a sx deve essere compreso tra 0 e 9 es: BC2H deve essere
scritto 0BC2H altrimenti verrebbe confusa con una stringa.
g
• Esempi corretti:
– 0FFh
– 0h
– 777O
– 11001B
• Esempi errati:
– FFh errata !
t
– 778O errata
11. a.a. 2007/2008
Architettura dei calcolatori
Dichiarazione dei dati
• Sintassi:
– <nome var> <mnemonico> op1, op2,… ;commento
• Lo mnemonico determina la dimensione in byte
– DB (define byte) ogni operando occupa 1 byte
– DW (define word) ogni operando occupa 1 word = 2bytes
( )g p p y
– DD (define double word) occupa 2 word = 4bytes
• Gli operandi possono essere dei valori o espressioni costanti
• Per riservare lo spazio di memoria si usa “?”
?
• Esempio:
DATA_SEG SEGMENT
DATA_BYTE
DATA BYTE DB 10,4,10H
10 4 10H
DATA_WORD DW 100,?,-5
DATA_DW DD 3*20,0FFFDH
DATA_SEGMENT ENDS
• Individuano 3 aree di memoria contigue lunghe ciascuna: 3 bytes, 6 bytes e 8 bytes
• Come definire un “array”
– <nome var> DB | DW| DD <dim> DUP (<elementi>)
| ( )
• duplica gli <elementi> specificati il numero di volte specificato da dim
12. a.a. 2007/2008
Architettura dei calcolatori
Modalità di Indirizzamento
• Esistono molti modi per indicare nell’istruzione dove trovare
l’operando
• REGISTRO: l’operando si trova in un registro
• IMMEDIATO: l’operando è nella istruzione
• MEMORIA se è i memoria, ci sono di
in i i diversi modi di calcolare
i di ll
MEMORIA:
l’indirizzo; alcune CPU prevedono molte modalità, maggiore
flessibilità e diminuzione del numero delle istruzioni; ma questo
implica reti logiche più complesse nella gestione ed un codice
operativo con più bit
13. a.a. 2007/2008
Architettura dei calcolatori
Metodi di indirizzamento in Memoria Intel
• Oltre che ai registri è possibile accedere alla memoria e questo può essere fatto in 17 modi di
indirizzamento (8086) per specificare un indirizzo di memoria. Questi possono essere raggruppati in 3
categorie:
– Indirizzamento diretto: si specifica l’indirizzo di memoria tramite un valore
p
numerico detto displacement, cioè spostamento.
– Indirizzamento indiretto tramite registro base: si specifica l’indirizzo di
memoria tramite il valore contenuto in uno tra i registri base BX o BP.
– Indirizzamento indiretto tramite registro indice: si specifica l’indirizzo di
memoria tramite il valore contenuto in uno tra i registri indice SI o DI.
• È possibile combinare queste tre modalità ottenendo tutte le possibili combinazioni. Per ricordare le
combinazioni valide è sufficiente memorizzare la tabella seguente (ognuno dei tre elementi può non
essere presente):
BX SI
Disp + +
BP DI
• Le modalità di indirizzamento viste si riferiscono sempre e solo al calcolo dell’offset, ovvero di un valore a
16 bit dato dalla somma dei tre possibili campi. A queste si deve sommare, scalato l’indirizzo di
segmento (modello di memoria segmentato)
14. a.a. 2007/2008
Architettura dei calcolatori
Modi di indirizzamento di I/O Intel
L’architettura INTEL ha uno spazio di indirizzamento specifico per l’I/O ed
istruzioni specifiche per accedervi.
Indirizzamento DIRETTO
L indirizzo
L’indirizzo può essere solo a 8 bit nell’istruzione (fino a 256 indirizzi diversi).
nell istruzione
AL serve per contenere il dato (a 8 bit)
in AL,PORTA1 ; AL I/O[PORTA1]
out PORTA2,AL ; I/O[PORTA2] AL
Indirizzamento INDIRETTO con registro DX
L’indirizzo è a 16 bit ed è nel registro DX
g
in AL,DX ; AL I/O[DX]
out DX,AL ; I/O[DX] AL
15. a.a. 2007/2008
Architettura dei calcolatori
Insieme delle istruzioni 8086
• Possiamo suddividere le istruzioni 8086 in gruppi funzionali:
– Trasferimento di dati
– Trasferimento di controllo
– Aritmetica binaria
– Logica binaria
– Shift e Rotate
– Operazioni su stringhe di dati
– Istruzioni per il controllo dei flag
g
– Aritmetica decimale (Binary Coded Decimal)
– Varie
• Di seguito esamineremo ogni gruppo di istruzioni, rimandando per i dettagli sulla
sintassi alle guide elettroniche fornite sul sito.
16. a.a. 2007/2008
Architettura dei calcolatori
Trasferimento di dati
• Fanno parte di questo gruppo:
– MOV dest,sorg Sposta il contenuto del secondo operando nel
primo
– XCHG dest,sorg Scambia il contenuto dei due operandi
– PUSH word Inserisce una word nello stack
– POP word Estrae una word dallo stack
– IN accum,porta Legge un dato dalla porta specificata
– OUT porta,accum Scrive un dato sulla porta specificata
• L istruzione
L’istruzione MOV è certamente la più usata e semplice da comprendere. XCHG consente di
scambiare due registri senza passare per una variabile temporanea.
• È importante notare che non è possibile muovere o scambiare dati tra memoria e memoria,
ma solo tra memoria e registri/valori.
• Le istruzioni di IN e OUT consentono di accedere ai registri delle periferiche collegate al
bus di sistema.
17. a.a. 2007/2008
Architettura dei calcolatori
Trasferimento di dati (2)
• Le istruzioni PUSH e POP lavorano con lo stack.
Per la precisione, l’istruzione PUSH AX è equivalente a:
SP = SP - 2
[SS:SP] = AX
Mentre POP AX equivale a:
AX = [SS:SP] = AX
[ ]
SP = SP + 2
• Quello che può sembrare strano è il fatto che il puntatore allo stack venga decrementato ad
ogni inserimento. In realtà questo consente una modalità di programmazione molto
compatta (nota anche come Modello di memoria Tiny) in cui tutti i segmenti hanno lo stesso
valore, i dati seguono immediatamente il codice e lo stack parte dalla fine del segmento:
0 FFFF
Codice Dati … Stack
• Questo modello di memoria ha un chiaro svantaggio, cioè limita il programma e tutti i suoi
dati ad un massimo di 64KB, ma elimina la necessità di occuparsi della segmentazione.
18. a.a. 2007/2008
Architettura dei calcolatori
Trasferimento di controllo
• Fanno parte di questo gruppo:
– CALL ind Esegue la procedura all’indirizzo ind
– RET Ritorna da una procedura
– INT num Esegue l’interruzione software num
– IRET Ritorna da una interruzione software
– JMP ind Salta all’indirizzo ind
– Jxx ind Salta all’indirizzo ind se è verificata la condizione xx
– LOOP ind Decrementa CX e se non è zero salta a ind
– LOOPxx ind Come LOOP, ma salta solo se è verificata xx
• L’istruzione più chiara è certamente JMP che può essere considerato un sostituto per “MOV IP i d” e
L’i t i iù hi t t JMP, h ò id t tit t IP,ind”
che chiarisce il concetto indicando che si “salta” in un’altra zona del programma.
• CALL è la versione di JMP che consente di tornare da dove si era venuti. Per fare questo prima del salto
viene eseguito un PUSH IP. Se si salta in un altro segmento viene prima salvato CS, poi IP ed infine si
salta. RET ritorna alla posizione precedente.
19. a.a. 2007/2008
Architettura dei calcolatori
Trasferimento di controllo (2)
• Le istruzioni di salto condizionato sono:
JA (JNBE) JAE (JNB) JB (JNAE) JBE (JNA) JE
(JNBE), (JNB), (JNAE), (JNA), JE,
JG (JNLE), JGE (JNL), JL (JNGE), JLE (JNG), JNE
A=above (superiore), B=below (inferiore), E=equal (uguale), G=greater
(maggiore), L=less (minore), N=not
• Questi salti fanno riferimento al risultato dell’operazione aritmetica CMP (compare) che
esegue una sottrazione ed aggiorna i FLAG in modo opportuno. Quindi queste
interpretazioni logiche non sono altro che una combinazione dello stato dei FLAG.
• Esistono salti che fanno esplicito riferimento ai FLAG:
• JC, JNC, JNO, JNP (JPO), JNS, JNZ, JO, JP (JPE), JS, JZ
C=carry (riporto), O=overflow, S=sign (segno), Z=zero, P=parity
• Esiste inoltre JCXZ che salta se CX è uguale a 0.
20. a.a. 2007/2008
Architettura dei calcolatori
Trasferimento di controllo (3)
JNE Jump if Not Equal ZF = 0
Istruzione Descrizione Salta se ...
JA Jump if Above CF = 0 e ZF = 0 JNG Jump if Not Greater ZF = 1 o SF ≠ OF
JAE Jump if Above or Equal CF = 0 JNGE Jump if Not Greater nor Equal SF ≠ OF
JB Jump if Below CF = 1 JNL Jump if Not Less SF = OF
JBE Jump if Below or Equal CF = 1 o ZF = 1 JNLE Jump if Not Less nor Equal ZF = 0 e SF = OF
JC Jump if Carry CF = 1 JNO Jump if No Overflow OF= 0
JE Jump if Equal ZF = 1 JNP Jump if No Parity (odd) PF = 0
JG Jump if Greater ZF = 0 e SF = OF JNS Jump if No Sign SF = 0
JGE Jump if Greater or Equal SF = OF JNZ Jump if Not Zero ZF = 0
JL Jump if Less SF ≠ OF JO Jump on Overflow OF =1
JLE Jump if Less or Equal JP Jump on Parity (even) PF = 1
ZF = 1 o SF ≠ OF
JNA Jump if Not Above CF = 1 o ZF = 1 JPE Jump if Parity Even PF = 1
JNAE Jump if Not Above nor Equal CF = 1 JPO Jump if Parity Odd PF = 0
JNB Jump if Not Below CF = 0 JS Jump on Sign SF = 1
JNBE Jump if Not Below nor Equal CF = 0 e ZF = 0 JZ Jump if Zero ZF = 1
JNC Jump if No Carry CF = 0
21. a.a. 2007/2008
Architettura dei calcolatori
Trasferimento di controllo (4)
• L’istruzione LOOP consente di eseguire i tipici cicli di una
programmazione strutturata. La variabile di controllo è CX e LOOP è
equivalente a un decremento di CX seguito da un salto se CX è diverso
CX,
da 0.
• Esistono inoltre LOOPE (LOOPZ) e LOOPNE (LOOPNZ) che combinano
il test CX diverso da 0 con il risultato di una operazione di compare
precedente.
• Infine l’istruzione INT consente di invocare le interruzioni software, che
per ora possiamo considerare come chiamate a funzione tramite un
indice numerato. Successivamente nel corso ne capiremo il reale
significato. Per ora basti sapere che INT è una CALL far (
g p (cioè inter-
segmento) che salva sullo stack anche il registro FLAG.
• Per questo motivo esiste un ritorno speciale IRET che prima estrae dallo
stack IP e CS e poi anche FLAG
FLAG.
22. a.a. 2007/2008
Architettura dei calcolatori
Implementare un If o un While
;if (c==‘5')
cmp c,‘5'
j
jne else
char c;
;then-part
...
call SeVero
if (c==‘5')
jmp endif
SeVero();
;else-part
;else part
else
else:
SeFalso();
call SeFalso
endif:
;while (n>0)
while:
cmp n,0
int n;
jle end_while
...
;loop body
;loop-body
while (n>0)
sub n,2
n-=2;
jmp while
end_while:
23. a.a. 2007/2008
Architettura dei calcolatori
Aritmetica binaria
• Fanno parte di questo gruppo:
– ADC dest,sorg Add with Carry
– ADD d t Addition
Additi
dest,sorg
– CMP dest,sorg Compare
– DEC dest Decrement
– DIV sorg Divide, Unsigned
– IDIV sorg Integer Divide, Signed
– IMUL sorg Integer Multiply, Signed
– INC dest Increment
– MUL sorg Multiply, Unsigned
M lti l U i d
– NEG dest Negate
– SBB dest,sorg Subtract with Borrow
– SUB dest,sorg Subtract
• Le operazioni più semplici sono certamente INC e DEC che aumentano o diminuiscono di
uno il valore di un registro o di una variabile in memoria
memoria.
24. a.a. 2007/2008
Architettura dei calcolatori
Aritmetica binaria
• Esistono poi ADD e SUB che effettuano somma e sottrazione del secondo
operando rispetto al primo e salvano il risultato nel primo.
• CMP è identico a SUB però non salva il risultato dato che serve unicamente per
SUB, risultato,
confrontare il contenuto di due registri e quindi effettua una differenza per
impostare i flag, ma non usa il risultato per nessuno scopo.
• ADC e SBB sono le versioni di somma e sottrazione che tengono conto di riporto
o prestito dell’operazione precedente, utili per effettuare elaborazioni con numeri
più grandi di 16 bit.
• MUL effettua la moltiplicazione di AL o AX con il byte o word passato come
parametro e mette il prodotto rispettivamente in AX o in DX:AX (cioè la parte alta
in DX e la parte bassa in AX). IMUL è l’equivalente per numeri con segno.
• DIV divide AX o DX AX per il b te o word passate come parametro e mette il
di ide DX:AX byte ord
quoziente e il resto in AL e AH o in AX e DX. IDIV è l’equivalente per numeri con
segno.
• Nel caso che il risultato della DIV sia troppo grande per il registro destinazione o
che il divisore sia 0, viene generato un INT 0h (Divisione per zero).
• La NEG produce il negato del registro passato come parametro.
25. a.a. 2007/2008
Architettura dei calcolatori
Esempio
Voglio realizzare la seguente operazione:
W = X+Y+24-Z
X+Y+24 Z
Devo svolgere il calcolo in vari passaggi:
mov AX,X ; metto X in AX
add AX,Y ; aggiungo Y al contenuto di AX
add AX,24 ; gli sommo 24
sub AX,Z ; gli sottraggo Z
mov W,AX ; memorizzo in W il contenuto di AX
…
X DW 34
Y DW 16
Z DW 20
W DW ?
26. a.a. 2007/2008
Architettura dei calcolatori
Esempio: Somma di valori a 32 bit
• Voglio sommare i due valori a 32 bit 0123 BC62 e 0012 553A
• Visto che nell’8086 i dati sono al massimo a 16 bit, posso svolgere il
calcolo i d step successivi. N l secondo step posso usare
l l in due t i i Nel dt
direttamente l’istruzione ADC.
mov ax,W10 ; si somma la word meno significativa
add ax,W20
mov W30,ax
mov ax,W11 ; si somma la word più significativa
adc ax,W21 ; e si somma con carry
mov W31,ax ; in W31 si mette il risultato
; dati
W11 dw 0123h
W10 dw bc62h
W21 dw 0012h
W20 dw 553ah
W31 dw ?
W30 dw ? ; non inizializzato
27. a.a. 2007/2008
Architettura dei calcolatori
Esempio 1
• Vediamo il primo esempio completo di programma assembly:
_TEXT segment
assume cs:_TEXT, ds:_TEXT, ss:_TEXT
org 100h
Leggi: mov ah,07h ; Questa è la funzione di lettura
int 21h ; di un carattere senza mostrarlo a video
cmp al,1Bh ; Il codice ASCII è 1B (ESC)?
je Fine ; Se sì, vai alla fine
mov ah,02h ; Funzione di scrittura a video
mov dl,al ; In DL ci va il carattere da visualizzare
int 21h
jmp Leggi ; Leggi un altro carattere
Fine: ret
_TEXT ends
end Leggi
28. a.a. 2007/2008
Architettura dei calcolatori
Esempio 1
• Tutto il programma è incluso in un unico segmento che abbiamo chiamato _TEXT (come fa
il C, ma è solo un nome si poteva scegliere anche qualcos’altro). La direttiva per dichiarare
segmenti è SEGMENT e viene chiusa da ENDS.
• Alla fine del programma si deve sempre includere END, seguito dall’etichetta da cui deve
cominciare il programma.
• La seconda riga informa l’assemblatore che CS conterrà l indirizzo del segmento _TEXT,
l assemblatore l’indirizzo TEXT
come anche DS ed SS.
• La terza riga contiene una direttiva per l’assemblatore che specifica che la prima istruzione
sarà all’indirizzo 100h nel segmento. Questo è lo standard per i file .COM del vecchio MS-
DOS ed è anche quello che utilizzeremo. Nei primi 100h byte c’erano dati del sistema
operativo, come la linea di comando e le istruzioni per terminare il programma.
• Dalla quarta riga vediamo una delle principali caratteristiche dell’assemblatore, cioè quella
di consentire la dichiarazione di etichette per indicare la posizione di una istruzione senza
conoscere l’indirizzo.
• Che valore verrà sostituito all’etichetta Leggi?
29. a.a. 2007/2008
Architettura dei calcolatori
Esempio 1
• L’etichetta Leggi indica l’indirizzo di una MOV che carica 07h nel registro AH. Poi viene
chiamato l’INT 21h. Questa è l’interruzione che consente di accedere alle funzioni del DOS.
La funzione richiesta viene passata in AH e la funzione 07h attende la pressione di un
tasto. Il risultato (il codice ASCII del tasto premuto) viene ritornato in AL.
• Il programma prosegue con una CMP, per verificare se l’utente ha premuto il carattere
ESC. Come già spiegato, CMP esegue una sottrazione t AL e 1Bh e i
ESC C ià i t tt i tra imposta il fl zero
t flag
(ZF). Possiamo allora verificare se sono uguali, con un JE. JE è infatti un sinonimo per
JZ,che però mette in evidenza (solo a livello concettuale) che la differenza è stata eseguita
con lo scopo di verificare una uguaglianza. Nel caso si sia premuto ESC, si salta
all’etichetta Fine.
• Il carattere letto viene poi visualizzato tramite la funzione 02h del DOS, che vuole il
p ,
carattere da visualizzare in DL. Infine si salta nuovamente all’etichetta Leggi.
• Nel caso si arrivi a Fine, viene eseguita una RET. Il DOS si è infatti preoccupato di fare una
PUSH dell’indirizzo di ritorno, o meglio ha eseguito il nostro programma facendo una CALL
all’Entry Point, ovvero l’etichetta che abbiamo messo a fianco della direttiva END.
30. a.a. 2007/2008
Architettura dei calcolatori
Esempio 2
_TEXT segment
assume cs: TEXT, ds: TEXT, ss: TEXT
org 100h
Leggi: mov ah,07h ; Questa è la funzione di lettura
int 21h ; di un carattere senza mostrarlo a video
cmp al,1Bh ; Il codice ASCII è 1B (ESC)?
je Fine ; Se sì, vai alla fine
mov Numero,al
call ScriviNumero
mov ah,02h ; Funzione di scrittura a video
mov dl,' ' ; In DL ci va il carattere da visualizzare
int 21h
jmp Leggi ; Leggi un altro carattere
Fine: ret
31. a.a. 2007/2008
Architettura dei calcolatori
Esempio 2 (segue)
In questo esempio vediamo come si
ScriviNumero:
mov ah,0
definiscono i dati tramite la direttiva
mov al,Numero
define byte ovvero DB. Dopo la
mov bl,16
direttiva DB è possibile inserire uno o
div bl
mov ah,0
più valori numerici separati da virgole,
mov si,ax
stringhe tra apici (ogni carattere è un
mov dl,CaratteriEsa[si]
byte) oppure un ? che indica dati non
mov ah,02h
int 21h
inizializzati (in realtà vale solo se
posizionato alla fine di un segmento,
mov ah,0
altrimenti è come scrivere 0).
mov al,Numero
mov bl,16
Inoltre è possibile notare come
div bl
xchg ah,al
CaratteriEsa[si] sia un indirizzamento
mov ah,0
indiretto tramite registro indice,
mov si,ax
equivalente al meno chiaro
mov
o d ,Ca atte
dl,CaratteriEsa[si]
sa[s ]
mov ah,02h
[CaratteriEsa+si].
int 21h
ret
CaratteriEsa db '0123456789ABCDEF'
Numero db ?
_TEXT ends
end Leggi
32. a.a. 2007/2008
Architettura dei calcolatori
Esempio 2 (segue)
La seconda parte potrebbe essere
proc ScriviNumero near
mov ah,0
scritta anche così. Cioè invece che
mov al,Numero
dichiarare una etichetta “normale”, si
mov bl,16
utilizza la direttiva PROC chiusa da
div bl
mov ah,0
ENDP. Non cambia nulla, a parte il
mov si,ax
fatto che si può esplicitare
mov dl,CaratteriEsa[si]
l’indicazione NEAR che indica una
mov ah,02h
int 21h
funzione all’interno dello stesso
segmento.
mov ah,0
mov al,Numero
mov bl,16
div bl
xchg ah,al
mov ah,0
mov si,ax
mov
o d ,Ca atte
dl,CaratteriEsa[si]
sa[s ]
mov ah,02h
int 21h
ret
CaratteriEsa db '0123456789ABCDEF'
endp ; ScriviNumero
Numero db ?
TEXT ends
end Leggi
33. a.a. 2007/2008
Architettura dei calcolatori
Logica binaria
• Fanno parte di questo gruppo:
– AND dest,sorg AND bit a bit
– NOT d t NOT bit a bit
dest
– OR dest,sorg OR bit a bit
– TEST dest,sorg Test
– XOR dest,sorg OR esclusivo bit a bit
• AND, NOT, OR e XOR eseguono l’operazione logica indicata sui bit dei registri forniti come
parametri. TEST è invece un AND che però non salva il risultato, un po’ come CMP, ma
modifica i FLAG. Questa istruzione serve per verificare se un certo bit di un byte o word è a
1.
34. a.a. 2007/2008
Architettura dei calcolatori
Shift e Rotate
• Fanno parte di questo gruppo:
– SHL dest,count Spostamento logico a sinistra
– SHR d t Spostamento logico a destra
S t tl i dt
dest,countt
– SAL dest,count Spostamento aritmetico a sinistra
– SAR dest,count Spostamento aritmetico a destra
– ROL dest,count Rotazione verso sinistra
– ROR dest,count Rotazione verso destra
– RCL dest,count Rotazione attraverso il carry verso sinistra
– RCR dest,count Rotazione attraverso il carry verso destra
• Gli shift logici spostano tutti i bit in una certa direzione, espellendo gli estremi nel carry e
inserendo degli zeri come nuovi bit.
• SAL è id ti a SHL mentre SAR i
identico SHL, t inserisce bit uguali al bit di segno originale, preservando
i li l ii l d
quindi il segno del numero.
• I rotate sono equivalenti agli shift, ma reinseriscono il bit “espulso” dalla parte opposta
come nuovo bit Le rotazioni attraverso il carry invece inseriscono il carry
bit. carry.
36. a.a. 2007/2008
Architettura dei calcolatori
Esempio 3
proc ScriviNumero near
In questo esempio è stata riscritta la
xor bh,bh
procedura ScriviNumero, utilizzando anche le
mov ah,02h
istruzioni logiche e la rotate.
mov ch,2
Nella prima riga, XOR viene utilizzato per
mov dh,Numero
Ripeti:
azzerare BH.
mov cl,4
Il parametro count per gli shift e i rotate può
ror dh,cl
essere soltanto 1 oppure CL. Att
lt t CL Attenzione
i
mov bl,dh
perché alcuni assemblatori consente anche
and bl,0fh
altri valori, ma questi funzionano soltanto dal
mov dl,CaratteriEsa[bx]
int 21h 80386 in avanti.
dec ch
Notare anche la mancanza di una CMP prima
jnz Ripeti
di JNZ.
ret
CaratteriEsa db '0123456789ABCDEF'
endp ; ScriviNumero
37. a.a. 2007/2008
Architettura dei calcolatori
Operazioni su stringhe di dati
• Fanno parte di questo gruppo:
– CMPS (CMPSB/CMPSW) Confronta stringhe di byte o word
– MOVS (MOVSB/MOVSW) Copia t i h
C i stringhe di b t o word
byte d
– LODS (LODSB/LODSW) Carica una stringa in AL o AX
– STOS (STOSB/STOSW) Scrive AL o AX in una stringa
– SCAS (SCASB/SCASW) Confronta AL o AX con una stringa
• Prefissi relativi a questo gruppo
– REP/REPE/REPZ Ripetono l’operazione se CX≠0 e se ZF=0,
poi CX=CX-1
– REPNE/REPNZ Ripetono l’operazione se CX≠0 e se ZF=1, poi
l operazione ZF 1,
CX=CX-1
• Queste operazioni sono istruzioni complesse che consentono di lavorare con stringhe di
dati in modo semplice. L’indirizzo della stringa sorgente è sempre DS:SI e quello
L indirizzo
destinazione è ES:DI.
• Ognuna di queste operazioni ha una forma con operandi a dimensione variabile e due
senza operandi (B per byte e W per word), ma in realtà la prima è solo un modo per
consentire più chiarezza nel codice e coincide esattamente con le altre due.
38. a.a. 2007/2008
Architettura dei calcolatori
Operazioni su stringhe di dati (2)
• Tutte le istruzioni stringa incrementano di uno in caso di byte o di due in caso di
word SI e DI. Se però il DF (flag direzione) è a 1 la direzione viene invertita e
quindi SI e DI vengono decrementati.
– MOVS(B/W) copia un dato da DS:SI a ES:DI
– LODS(B/W) carica un dato da DS:SI in AL o AX
– STOS(B/W) scrive il dato da AL o AX a ES:DI
• Solitamente per MOVS e STOS si utilizza il prefisso REP che consente di
ripetere la copia o la scrittura CX volte. LODS si può ripetere, ma è totalmente
inutile, dato che AL/AX viene continuamente sovrascritto.
– CMPS(B/W) confronta il dato in DS:SI con quello in ES:DI
– SCAS(B/W) confronta il dato in DS:SI con AL o AX
• CMPS e SCAS vengono tipicamente ripetuti con REPE/Z o REPNE/Z a seconda
g p p
che si voglia continuare fino a che il dato è uguale o diverso.
39. a.a. 2007/2008
Architettura dei calcolatori
Istruzioni per il controllo dei flag
• Fanno parte di questo gruppo:
– CLC/STC Clear/Set Carry Flag (Pone CF a zero o a
uno)
– CLD/STD Clear/Set Direction Flag (Pone DF a zero o
a uno)
– CLI/STI Clear/Set Interrupt-Enable Flag (Pone IF a zero o a
uno)
– CMC Complement Carry Flag (Inverte lo stato di CF)
– LAHF Copia FLAG in AH
– SAHF Copia AH nei FLAG
p
– POPF Estrae i FLAG dallo stack
– PUSHF Memorizza i FLAG sullo stack
• Queste istruzioni ti i
Q t i t i i tipicamente vengono usate CLD e STD prima d ll i t i i stringa, CLC
t t i delle istruzioni t i CLC,
STC e CMC prima di alcune operazioni aritmetiche su numeri grandi, CLI e STI prima e
dopo l’esecuzione di sezioni che lavorano con l’hardware o con le tabelle degli interrupt.
• Le altre servono tipicamente nelle routine di risposta agli interrupt
interrupt.
40. a.a. 2007/2008
Architettura dei calcolatori
Aritmetica decimale (Binary Coded Decimal)
• Fanno parte di questo gruppo:
– AAA ASCII Adjust after Addition
– AAD ASCII Adj t b f
Adjust before Di i i
Division
– AAM ASCII Adjust after Multiply
– AAS ASCII Adjust after Subtraction
– DAA Decimal Adjust after Addition
– DAS Decimal Adjust after Subtraction
• Non vedremo i dettagli di queste istruzioni, che servono per utilizzare il formato numerico
Binary Coded Decimal (BCD). Questo formato prevede che i numeri compaiano in forma
decimale, con una cifra per byte (formato unpacked-BCD) o due cifre per byte (formato
packed-BCD).
41. a.a. 2007/2008
Architettura dei calcolatori
Varie
• Fanno parte di questo gruppo:
– LEA dest,source Carica l’indirizzo di source in dest
– LDS dest,source Carica il puntatore all’indirizzo source in DS:dest
p
,
– LES dest,source Carica il puntatore all’indirizzo source in ES:dest
– NOP Non fa niente (no operation)
– XLAT Estrae un dato da una tabella in memoria
• LEA carica l’indirizzo di variabili in memoria in un registro, risolvendo eventuali indici o scostamenti.
• LDS e LES servono per caricare una variabile puntatore far con una sola istruzione.
• XLAT è equivalente ad una MOV AL,[BX+AL] (istruzione sintatticamente errata). Se ad esempio abbiamo
una serie di dati (byte) in memoria e vogliamo estrarre il 3°, possiamo caricare in BX l’indirizzo dei dati e
3 l indirizzo
in AL 3.
• Operatore OFFSET
– Formato: OFFSET <variabile o label>
– L’operatore OFFSET restituisce il valore dell’offset di una variabile o della
label
– P ò essere usato i alternativa all’istruzione LEA solo nei casi più semplici
Può in l i ll’i i l i i iù li i
– – Esempio:
MOV AX, OFFSET VAR
LEA AX, VAR
,
(se Var è una variabile => Sono equivalenti)
42. a.a. 2007/2008
Architettura dei calcolatori
Esempio 4
Questa ennesima versione di
proc ScriviNumero near
ScriviNumero, mostra l’uso che si può
mov dh,Numero
mov cl,2
fare di XLAT.
Ripeti:
Notare che è stato invertito il verso
Nt h tt i tit
rol dh,1
della rotazione e che è stata usata
rol dh,1
l’istruzione LOOP per la ripetizione.
rol dh,1
rol dh,1
Il parametro della XLAT è sempre [BX]
mov al,dh
che va infatti caricato opportunamente.
and al,0fh
Anche se non viene indicato [BX], il
mov bx,offset CaratteriEsa
comportamento di XLAT non cambia.
xlat
Notare anche che se vogliamo
mov ah,02h
mov dl,al
l’indirizzo di una variabile dobbiamo
int 21h
usare la direttiva offset.
loop Ripeti
ret
CaratteriEsa db '0123456789ABCDEF'
endp ; ScriviNumero
43. a.a. 2007/2008
Architettura dei calcolatori
Esempio 5 – Le stringhe
_TEXT segment ; Visualizzo Stringa2
assume cs:_TEXT, ds:_TEXT, ss:_TEXT mov cl,Stringa2
org 100h mov si,offset Stringa2 + 1
mov ah,02h
Inizio: ; Copio Stringa2 in Stringa1 Stampa2:
xor ch,ch lodsb
mov cl,Stringa2 mov dl,al
mov Stringa1,cl int 21h
mov si,offset Stringa2 + 1
g loop
p Stampa2
p
mov di,offset Stringa1 + 1
rep movsb ; Termino il programma
Fine: ret
; Visualizzo Stringa1
mov cl,Stringa1
cl Stringa1 ; Dati del programma
mov si,offset Stringa1 + 1 Stringa1 db ?
mov ah,02h db 255 dup (?)
Stampa: lodsb Stringa2 db 16,'Prova di stringa'
mov dl,al db 255-16 dup (?)
int
it 21h
loop Stampa _TEXT ends
; Riempio Stringa2 di ‘*’ end Inizio
mov al,'*'
mov cl,100
mov Stringa2,cl
mov di,offset Stringa2 + 1
rep stosb
44. a.a. 2007/2008
Architettura dei calcolatori
Esempio 5
• In questo esempio vengono utilizzate le istruzioni per le stringhe.
• Per comodità si sono definite le stringhe al modo del PASCAL, ovvero
con un b t iniziale che contiene l l
byte i i i l h ti la lunghezza d ll stringa e uno spazio
h della t i i
di 255 byte. Notare che è stata usata la direttiva dup per allocare lo
spazio necessario. La sintassi è:
[numero di ripetizioni] dup ( dato da ripetere )
• Quindi Stringa1 è l’indirizzo di una struttura di 256 byte, in cui il primo
indica il numero di caratteri effettivamente presenti nel buffer di 255
caratteri successivo.
• Stringa2 è analoga, ma viene inizializzata con un testo.
• Il programma copia Stringa2 in Stringa1, ne visualizza il contenuto,
riempie Stringa2 di asterischi e mostra il risultato.
• Provate a modificare il programma in modo che la parte che esegue la
visualizzazione sia una procedura da invocare con una CALL.
45. a.a. 2007/2008
Architettura dei calcolatori
Esempio 6 – Uso di più segmenti
_TEXT segment para public 'CODE' ; Visualizza stringa
assume cs:_TEXT, ds:_DATA, ss:_STACK mov ah,09h
mov dx,offset str_ACapo
; inizializiamo DS in modo che punti al int 21h
; segmento dati
Inizio: mov ax,_DATA ; Chiamo la funzione DOS per terminare
mov ds,ax ; i programmi
; Visualizza stringa mov ah,4ch
mov ah,09h
, mov al,00h
,
mov dx,offset str_Messaggio1 int 21h
_TEXT ends
int 21h
; Input di un carattere (viene ritornato
_DATA segment para public 'DATA'
; in al)
mov ah,01h
ah 01h str Messaggio1 db 'Digita un carattere:
Digita
int 21h ','$'
; Memorizzo il carattere str_ACapo db 0dh,0ah,'$'
mov Carattere,al str_Messaggio2 db 'Hai premuto il
; Visualizza stringhe carattere: ','$'
mov ah,09h
mov dx,offset str_ACapo Carattere db ?
_DATA ends
int 21h
mov ah,09h
_STACK segment para stack
g p 'STACK'
mov dx,offset str Messaggio2
gg
int 21h ; Dimensione dello stack
; Output del carattere premuto dw 32 dup (?)
_STACK ends
mov ah,02h
mov dl,Carattere
end Inizio
int 21h
46. a.a. 2007/2008
Architettura dei calcolatori
Esempio 6
• In questo esempio vediamo un programma con più segmenti (che quindi
diventerà un EXE e non un COM.
• Non ’è ll
N c’è nulla di particolarmente strano nel programma che si li it a
ti l tt l h i limita
visualizzare stringhe e caratteri con le funzioni del DOS. Attenzione che
la funzione per stampare stringhe in DOS vuole un carattere ‘$’ alla fine
della stringa.
• Per dichiarare un segmento di stack è necessario riservare un po’ di
spazio a differenza di prima e quindi si sono riservate 32 word.