Muovere i dati è una dei principali compiti di un programma Assembly, abbiamo già visto che sono possibili solo i seguenti spostamenti:
memoria <--> registro
registro <--> registro
Non sono possibili spostamenti da memoria a memoria e per far ciò si deve
ricorrere all'uso di registri di supporto:
memoria <--> registro <--> memoria
Esempi di spostamenti memoria memoria, NON AMMESSI, sono (in linguaggio macchina):
mov byte/word [100],[200] mov byte/word [bx],[50]Esercizio (facile!): espandere questi spostamenti usando ad es. al/ax come registro di supporto.
> MOV
Il metodo più comune per spostare i dati è quello di utilizzare l'istruzione
MOV come abbiamo già visto nei precedenti esempi. La sintassi completa
dell'istruzione è la seguente:
MOV < registro|memoria > , < registro|memoria|valore imm. >
Alcuni esempi sono:
mov ax,7 ;valore --> registro
mov mem,45 ;valore --> memoria
mov ax,bx ;registro --> registro
mov mem[bx],7 ;valore --> memoria (indiretto)
...
...
> XCHG
XCHG < registro|memoria > , < registro|memoria >
Ad esempio:
xchg ax,bx ; pippo:=ax;
; ax:=bx;
; bx:=pippo;
Attenzione che non è possibile fare lo scambio di due dati entrambi in memoria.
> LAHF e SAHF
Per esaminare il registro dei flag esistono queste due istruzioni: LAHF che
carica in AH, SAHF che li salva. Spero vi sia sorto un dubbio. Come faccio a
far stare l'intero registro di flag in 8 bit ??
Bene quete due instruzioni lavorano solo sugli 8 bit meno significativi del
registro (che è stato descritto per intero nel tutorial 4).
Esistono comunque altre due istruzioni per salvare e ripristinare l'intero
registro di flag nello Stack ma le vedremo dopo.
-- CONVERTIRE LE DIMENSIONI DI UN DATO --
Siccome trasferire dati tra registri di diversa dimensione non è consentito,per
fare questo tipo di operazione si devono prendere alcuni accorgimenti.
Prima di tutto ci si comporta in modo diverso a seconda che il dato abbia o no
il segno.
Nel caso di SIGNED VALUE l'Assembly mette a disposizione due istruzioni:CBW
(Convert Byte to Word) e CWD (Convert Word to Doubleword).
CBW converte il dato a 8 bit con segno contenuto in AL mettendolo in AX (16bit).
CWD come la precendente prende il dato in AX (16bit) e lo mette in DX:AX.
Per capire meglio vediamo un esempio:
.DATA
mem8 DB -5
mem16 DW -5
.CODE
....
....
mov al,mem8 ;mette in AL -5 (FBh)
cbw ;converte (8-->16)(FBh-->FFFBh) in AX
mov ax,mem16 ;AX=-5 (FFFBh)
cwd ;converte (16-->32)(FFFBh-->FFFF:FFFBh) in DX:AX
>LEA
L'istruzione LEA (Load Effective Address) carica un puntatore di tipo NEAR nel
registro specificato, la sua sintassi è :
LEA registro,memoria
Ad esempio:
LEA dx,stringa ;carica in dx l'offset di stringa
equivale a
MOV dx,OFFSET stringa
NOTA : il secondo modo (con l'uso di MOV) in tal caso è più veloce essendo
l'OFFSET una costante nota all'assembler che quindi non deve essere calcolata.LEA dx,stringa con MOV dx,OFFSET stringa.
L'istruzione LEA è più utile per calcolare l'indirizzo indiretto:
LEA dx,stringa[si] ;mette in dx l'indirizzo di stringa[si]
equivale in linguaggio macchina aLEA dx,[si+OFFSET stringa]>LDS e LES
.DATA
stringa DB "A me piace la Nutella"
fpStr DD stringa ;Puntatore FAR a stringa
punt DD 100 DUP(?)
.CODE
...
...
les di,fpStr ;mette l'indirizzo in ES:DI
lds si,punt[bx] ;mette l'indirizzo in DS:SI
-- OPERAZIONI SULLO STACK --
>PUSH e POP
Queste sono le due istruzioni base rispettivamente per scrivere e leggere nello
stack, esse modificano automaticamente il valore di SP.
La loro sintassi è la seguente:
PUSH < registro|memoria|valore >
POP < registro|memoria >
NOTA: PUSH valore è disponibile solo sui processori 80186 e superiori.
Attenzione che le dimensioni di una "cella" di stack è di 2 byte.
mov bp,sp ;preparo bp alla base dello stack
push ax ;salva il primo
push bx ;salva il secondo
push cx ;...
...
...
pop cx ;prelevo il terzo
pop bx ;prelevo il secondo
pop ax
Una breve nota: lo stack a differenza di altre strutture comincia a memorizzare
i dati nelle locazioni alte di memoria e via via scende verso il basso man mano
che aggiungo dati.
mov bp,sp
push ax ;salvo i 3 regsitri
push bx
push cx
...
...
mov ax,[bp-2] ;prelevo ax
mov bx,[bp-4] ;prelevo bx
mov cx,[bp-6] ;...
A questo punto però non ho vuotato lo stack (ho solo letto i valori) per
ripristinarlo come prima devo aggiungere l'istruzione:
sub sp,6
sottraggo cioè 6 byte dallo Stack Pointer (2 byte per ogni registro).
Stack
High Mem ---------
^ | ??? | <-- BP
| |-------|
| | ax | <-- BP-2
| |-------|
| | bx | <-- BP-4
| |-------|
| | cx | <-- BP-6 = SP
Low Mem |-------|
| |
Questo prima della sub.
>PUSHF e POPF
Sono istruzioni che salvano nello stack e ripristano il valore del registro di
flag.
Per processori 386 e sup. ci sono anche le due istruzioni rispettive per i
registri a 32 bit : PUSHFD e POPFD.
>PUSHA e POPA
Salvano e ripristinano tutti i registri nel seguente ordine: AX,CX,DX,BX,SP,BP,
SI e DI. Il valore di SP che viene salvato è quello prima dell'istruzione PUSHA
Naturalmente la POPA li estrae in ordine inverso.
Per processori 386 e sup. ci sono anche le due istruzioni rispettive per i
registri a 32 bit : PUSHAD e POPAD.
-- SCRIVERE E LEGGERE SULLE PORTE DI I/O --
Le porte sono il mezzo per far comunicare la CPU con le schede presenti nel
computer. Ogni porta ha un suo numero che può essere usato per accedervi.
>IN e OUT
IN legge il dato dalla porta e OUT lo manda alla porta, la loro sintassi è:
IN accumulatore,< numero porta|DX >
OUT < numero porta|DX >,accumulatore
NOTA: ricordo che l'accumulatore è per le famiglie 80x86 il registro ax che può
essere usato a 8,16 o 32 bit (al/ah,ax,eax).
TUT7.COM TUT7.ASM
sound EQU 61h ;porta che controlla lo speaker
timer EQU 42h ;porta che fa suonare lo speaker
on EQU 00000011b ;i 2 LSB attivano lo speaker
in al,sound ;preleva lo stato attuale della porta
or al,on ;attiva lo speaker
out sound,al ;rimanda il valore
mov al,250 ;comincia da 250
suona: out timer,al
mov cx,0FFFFh ;aspetta "FFFF volte"
aspetta:loop aspetta
dec al
jnz suona
in al,sound
and al,NOT on ;spegne lo speaker
out sound,al ;ripristina la porta
Nei processori 80186 e superiori sono state introdotte altre istruzioni per
leggere e scrivere stringhe :
INS < [ES:]destinazione >,DX
INSB
INSW
e le rispettive out:
OUTS
OUTSB
OUTSW
La INS e la OUTS non accettato un valore immediato per l'indirizzo e si deve
far uso di DX.Per adesso mi fermo qui, questa volta non vi presento nessun programma, più che altro perchè non mi viene in mente niente su questo argomento; comunque potete sempre provare a scrivere qualcosa voi e se incontrate difficoltà, beh fatemelo sapere cercherò di aiutarvi.
| Assembly Page di Antonio |
|