Assembly Programming Tutorial #8 – Istruzioni Logico – Aritmetiche

35 Views 0 Comment

Le istruzioni logico – aritmetiche sono istruzioni eseguite dalla ALU, Il risultato di un’istruzione L/A modifica lo stato del registro dei flag e richiedono sempre uno o due operandi.

Classi di istruzioni:

  • Somma, Sottrazione, Negazione
  • Moltiplicazione, Divisione
  • Operazioni logiche (AND, OR, XOR, NOT)
  • Incremento e decremento
  • Shift e rotazione
  • Confronto e test

IL REGISTRO DEI FLAG

Il registro dei flag è composto da 16 bit, ognuno dei quali può assumere valore 1 or 0

Carry Flag (CF)
Il flag è impostato a 1 quando il risultato di un’operazione genera un overflow senza segno
Zero Flag (ZF)
Il flag è impostato a 1 quando il risultato di un’operazione è pari a zero
Sign Flag (SF)
Il flag è impostato a 1 quando il risultato di un’operazione è negativo
Overflow Flag (OF)
Il flag è impostato a 1 quando il risultato di un’operazione genera un overflow con segno
Parity Flag (PF)
Il flag è impostato a 1 quando nel risultato di un’operazione c’è un numero pari di 1

OPERAZIONI ARITMETICHE

Le istruzioni aritmetiche vengono raggruppate in base alle 4 operazioni aritmetiche fondamentali:

ADDIZIONE:

  • ADD = Addizione
  • ADC = Addizione con riporto
  • INC  = Incremento
  • NEG = Negazione

 

SOTTRAZIONE

  • SUB = Sottrazione
  • SBB = Sottrazione con riporto
  • CMP = Confronto tra due valori
  • DEC = Decremento

 

MOLTIPLICAZIONE

  • MUL = Moltiplicazione senza segno
  • IMUL = Moltiplicazione con segno

 

DIVISIONE

  • DIV = Divisione senza segno
  • IDIV = Divisione con segno

OPERAZIONI DI SOMMA E DIFFERENZA

Le operazioni di somma e differenza vengono eseguite tramite le istruzioni ADD, ADC, SUB, SBB, CMP
La sintassi di queste istruzioni è uguale per tutte:
<istruzione> <op1>, <op2>
<op1> e <op2> possono essere registri, valori immediati o indirizzi di memoria.
Al termine dell’operazione, il risultato è sempre memorizzato nel primo operando (tranne che per l’istruzione CMP), ma non tutte le combinazioni di operandi sono lecite, infatti:
Un valore immediato non può essere primo operando e  sono inoltre vietate somme/differenze tra indirizzi di memoria.

OPERAZIONI DI SOMMA

L’operazione di somma può essere eseguita tramite l’istruzione ADD.
La sua sintassi è la seguente:

ADD <op1>, <op2>
L’istruzione ADD addiziona al primo operando (che rappresenta la destinazione del risultato) il secondo operando
Esempio:
MOV AL, 2                ; AL = 2
MOV AH, -7              ; AH = -7
ADD AL, AH              ;AL = -5
RET
L’operazione di somma può essere eseguita tramite l’istruzione ADC (ADdition with Carry)
La sua sintassi è uguale all’ istruzione ADD.
ADC addiziona al primo operando (che rappresenta la destinazione del risultato) il secondo operando e il valore del bit di CF (carry flag).

OPERAZIONI DI DIFFERENZA

L’operazione di differenza viene eseguita tramite l’istruzione SUB
Sintassi: SUB <op1>, <op2>
L’istruzione SUB sottrae dal primo operando (che rappresenta la destinazione del risultato) il secondo operando.
Esempio:
MOV AX, 10      ; AX = 10
SUB AX, 1          ; AX = 9
RET

L’operazione di differenza può essere eseguita tramite l’istruzione SBB
Sintassi: SBB <op1>, <op2>
L’istruzione SBB sottrae dal primo operando (che rappresenta la destinazione del risultato) il secondo operando e il valore del bit di CF (carry flag).

L’operazione di differenza può essere eseguita anche tramite l’istruzione CMP, al solo fine di effettuare un confronto fra gli operandi.
Sintassi: CMP <op1>, <op2>
L’istruzione CMP sottrae dal primo operando il secondo operando, modificando solo i bit di flag.
Il risultato della sottrazione eseguita da CMP non viene memorizzato e i flag assumono valore 0 o 1 in base al risultato della sottrazione.
Esempio:
MOV AX, 12
MOV BX, 5
CMP AX, BX                       ;ZF(zero flag) = 0 (AX e BX sono diversi!)

OPERAZIONI DI INCREMENTO E DECREMENTO

Le operazioni di incremento e decremento (somma e differenza di 1) vengono eseguite tramite le istruzioni

INC, DEC
La sintassi di queste istruzioni è analoga per entrambe:
<istruzione> <op1>
<op1> può essere:

  • Un registro;
  • Un indirizzo di memoria.

Al termine dell’operazione, l’operando risulta incrementato o decrementato di 1

L’ ISTRUZIONE NEG

Il linguaggio Assembly mette a disposizione un’ istruzione particolare di nome NEG. La si usa per calcolare il negativo di un numero, il quale viene espresso in COMPLEMENTO A 2.
Sintassi: NEG <op1>
<op1> può essere:

  • Un registro;
  • Un indirizzo di memoria.

L’istruzione NEG altro non fa che Invertire tutti i bit dell’operando ed aggiunge 1 all’ operando invertito.

OPERAZIONI DI PRODOTTO E DIVISIONE

Le operazioni di prodotto e divisione vengono eseguite tramite le istruzioni MUL, IMUL, DIV, IDIV e la sintassi di queste istruzioni è analoga per tutte:
<istruzione> <op1>
<op1> può essere:

  • Un registro;
  • Un indirizzo di memoria.

Le istruzioni MUL, IMUL, DIV, IDIV utilizzano i registri AX e DX; inoltre le istruzioni MUL, IMUL influenzano solo i flag CF (carry) e OF (overflow), mentre le istruzioni DIV, IDIV lasciano i flag indefiniti.

OPERAZIONI DI PRODOTTO

Con la sintassi dell’istruzione viene specificato solo un fattore della moltiplicazione (<op1>).
Il secondo fattore viene assunto di default tramite il registro AX
N.B. Entrambi gli operandi devono avere la stessa grandezza (byte o word). Il risultato del prodotto è memorizzato in uno spazio di lunghezza doppia rispetto a quella dei fattori.
Caso 1: byte × byte
se <op1> è pari a 1 byte, lo stesso viene moltiplicato per il contenuto di AL e il risultato è memorizzato in AX
Caso 2: word × word
se <op1> è pari a 1 word, lo stesso viene moltiplicato per il contenuto di AX e il
risultato è memorizzato in [DX : AX], ciò vuol dire che DX contiene la word più significativa, AX la word meno significativa.

OPERAZIONI DI DIVISIONE

Con la sintassi dell’istruzione viene specificato solo il secondo fattore (divisore) della divisione (<op1>).
Il primo fattore (dividendo) viene assunto tramite i registri AX e DX.
N.B. Il dividendo occupa uno spazio doppio rispetto al fattore specificato (divisore)
Il risultato della divisione è duplice: quoziente e resto:
Quoziente e resto sono memorizzati in uno spazio di lunghezza pari alla metà rispetto a quella del dividendo (ossia pari a quella del fattore specificato)

Caso 1: Divisore (<op1>) lungo 1 byte
Il contenuto di AX (dividendo) viene diviso per <op1> (divisore), il quoziente è memorizzato in AL e il resto è memorizzato in AH.

Caso 2: Divisore (<op1>) lungo 1 word
il contenuto di [DX : AX] (dividendo) viene diviso per <op1> (divisore), il quoziente è memorizzato in AX e il resto è memorizzato in DX
Quindi DX contiene la word più significativa del dividendo, AX la word meno significativa.

 

Nel prossimo articolo parleremo del Flusso di esecuzione, se invece ti sei perso lo scorso articolo, si è visto come scrivere il Primo programma.

Stai cercando altre guide? Allora dai uno sguardo alla nostra raccolta dedicata alla Programmazione Assembly.

Alla prossima!


Continua a seguirci su:

Facebook Instagram Telegram Rss