Muovere i dati è una dei principali compiti di un programma Assembly, abbiamo già visto che sono possibili solo i seguenti spostamenti:
memoria <--> registro registro <--> registroNon sono possibili spostamenti da memoria a memoria e per far ciò si deve ricorrere all'uso di registri di supporto:
memoria <--> registro <--> memoriaEsempi 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,memoriaAd esempio:
LEA dx,stringa ;carica in dx l'offset di stringaequivale a
MOV dx,OFFSET stringaNOTA : 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 a
LEA 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 axUna 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,6sottraggo 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 >,accumulatoreNOTA: 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 portaNei processori 80186 e superiori sono state introdotte altre istruzioni per leggere e scrivere stringhe :
INS < [ES:]destinazione >,DX INSB INSWe le rispettive out:
OUTS OUTSB OUTSWLa 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 |
|