ce este limbajul de asamblare

55
Ce este limbajul de asamblare? In momentul in care un fisier sursa (de exemplu C) este compilat, el trece prin urmatoarele stagii: 1.preprocesare 2.compilare 3.asamblare 4.link-editar Ce ne intereseaza din aceste stagii sunt asamblarea si link-editarea. Primele programe pentru calculator se scriau in format binar, unde secvente de biti reprezentau instructiuni pentru procesor. Spre exemplu: primi 4 biti = tipul instructiunii (adunare, scadere, etc.) 4 biti = adresa primul operand (sursa) 4 biti = adresa celui de-al doilea operand (destinatia) Unul din primele PC-uri care folosea aceasta metoda de programare era Altair 8800 . Programele se codificau prin comutarea unor switch-uri, si aveau ca efect diferite jocuri de lumini. Deoarece formatul binar este un model de programare destul de greoi, s-a trecut la limbajul de asamblare. Limbajul de asamblare formeaza o relatie 1:1 intre instructiunile binare si secvente de text. Exemplu: In loc sa codificam instructiunile asa 1110 1001 0110

Upload: drajneanu-gelu

Post on 15-Jan-2016

90 views

Category:

Documents


3 download

DESCRIPTION

limbaj de asamblare arhitectura sistemelor de calcul

TRANSCRIPT

Page 1: Ce Este Limbajul de Asamblare

Ce este limbajul de asamblare?

In momentul in care un fisier sursa (de exemplu C) este compilat, el trece prin urmatoarele stagii:1. preprocesare2. compilare3. asamblare4. link-editarCe ne intereseaza din aceste stagii sunt asamblarea si link-editarea.

Primele programe pentru calculator se scriau in format binar, unde secvente de biti reprezentau instructiuni pentru procesor.Spre exemplu:

primi 4 biti = tipul instructiunii (adunare, scadere, etc.) 4 biti = adresa primul operand (sursa) 4 biti = adresa celui de-al doilea operand (destinatia)Unul din primele PC-uri care folosea aceasta metoda de programare era Altair 8800. Programele se codificau prin comutarea unor switch-uri, si aveau ca efect diferite jocuri de lumini.

Deoarece formatul binar este un model de programare destul de greoi, s-a trecut la limbajul de asamblare.Limbajul de asamblare formeaza o relatie 1:1 intre instructiunile binare si secvente de text.Exemplu:In loc sa codificam instructiunile asa

1110 1001 0110

Putem scrie cod de asamblare de genul

add A, B

Acest exemplu putand fi un candidat pentru o instructiune care aduna A cu B si depune rezultatul in A.

Asamblorul este un program care transforma instructiunile din limbaj de asamblare in format binar. Acesta primeste la intrare un fisier cu extensia ”.asm”,

Page 2: Ce Este Limbajul de Asamblare

si creeaza un fisier cu extensia ”.obj”. Codul in limbaj de asamblare se poate scrie in mai multe module/fisiere, din care sa rezulte mai multe fisiere obj.

Link-editorul este cel care se ocupa de legarea modulelor obj intr-un singur fisier executabil, moment in care se face si maparea in memorie .Fisierele obiect generate de asamblor nu se pot executa, deoarece contin cod relocabil, care nu are o mapare fixa in zona de memorie. La momentul executiei, fiecare program are o zona bine stabilita de memorie in care se afla, insa sistemul de operare este cel care “ii face loc” acestuia in memoria virtuala (RAM/HDD). Ca atare, adresele absolute ale datelor si instructiunilor nu vor fi cunoscute decat la runtime, si pot diferi de la o executie la alta.

In momentul in care ajungi sa lucrezi pe un OS modern (Linux, Windows, Mac OS, etc.) este nevoie de mult mai multe concepte de sisteme de operare pentru a arata cum un procesor influenteaza organizarea unui calculator, chiar si la nivelul software. Spre exemplu, apar probleme in explicarea conceptelor de sistem de intreruperi (functii speciale, care ajuta la formarea legaturii intre OS si hardware).

De ce sa invatam asamblare ?

Programarea in limbaj de asamblare, ca atare, nu se mai practica pentru dezvoltarea proiectelor mai ample, codul ajungand foarte stufos si greu de intretinut.

In unele limbaje, precum C sau C++, se poate folosi inline assembly, unde sintaxa de C/C++ poate fi amestecata cu cod de asamblare, facandu-se astfel optimizari direct in cod.

In aplicatii critice, cum ar fi bootloader-ele sau drivere de kernel, limbajul de asamblare inca este folosit.

Pe de alta parte, insa, compilatoarele actuale, precum GCC sau Intel C++ Compiler, au mecanisme foarte avansate de optimizare, ceea ce poate face redundante incercarile noastre de a scrie cod rapid. Desi acestea au si avantajul ca programul poate fi lasat in intregime in sintaxa de C, mai lizibila - cunoasterea limbajului de asamblare va poate ajuta si sa scrieti cod mai bun de C.Un alt beneficiu este intelegerea mai usoara a materiilor precum Sisteme de Operare, acolo unde procesorul are o implicare directa in organizarea sistemului de operare, sau Compilatoare.

Page 3: Ce Este Limbajul de Asamblare

Dobandirea acestor notiuni va poate ajuta in alegerea unui procesor/microcontroller, poate ajuta sa intelegeti ce inseamna un set de instructiuni (unele seturi de instructiuni fiind specifice unui anumit procesor si mai facile pentru anumite aplicatii). Prezenta unui anumit set de instructiuni adesea implica si prezenta unui modul special in procesor, pretat pe acele instructiuni.

……………………………………………….

Pentru a putea scrie cod in limbaj de asamblare vom avea nevoie de 3 baze numerice:

zecimala (baza 10) binara (baza 2) hexazecimala (baza 16) octala (baza 8)

Suportul hardware. Procesoare. Registre. Flaguri

Ce este un procesor?

Un procesor este un ansamblu de circuite combinationale si secventiale.Atat partea de control, cat si UAL-ul sunt facute din circuite combinationale (combinatii de porti logice).

Ierarhia de memorii dintr-un PC

Registrele reprezinta o parte din circuitele secventiale din procesor. Ele sunt memorii SRAM construite din mai multe bistabile puse in paralel, cate unul pentru fiecare bit. Valorile stocate in ele sunt cele folosite efectiv la calcularea datelor.Registrele sunt memorii foarte rapide, insa si foarte costisitoare, motiv pentru care exista memorii externe procesorului, mult mai mari, numite RAM.Memoria RAM contine datele si instructiunile unui program. Pentru a intelege de ce este mai ieftina fabricarea acesteia in capacitati mai mari, vom spune doar ca fiecare bit reprezentat in RAM are nevoie de un singur tranzistor (pentru a activa/dezactiva accesul la valoarea stocata) si de un condensator (care pastreaza efectiv vaoarea)Memoriile, find externe procesorului, sunt foarte costisitoare in termeni de timp de

Page 4: Ce Este Limbajul de Asamblare

accesare (cateva ordine de marime mai lente). De acea este bine ca operatiile sa lucreze cat mai mult cu registrele procesorului, si cat mai putin cu memoria!

Structura instructiunilor

Pentru a face efectiv operatii cu procesorul, operanzii trebuiesc adusi efectiv din memorie in registre. Toata logica combinationala se bazeaza pe valorile stocate in registre. Din acest motiv, majoritatea instructiunilor unui procesor va obliga sa aveti ca operanzi cel putin un registru. Desi cel de-al doilea operand poate fi o zona de memorie, si acesta ajunge intr-un registru transparent din procesor.O instructiune se poate sparge in cateva instructiuni mai mici, atomice, mai usor de inteles pentru procesor.

Instructiunile mai mici alcatuiesc ceea ce se numeste microcod. Acesta este specific fiecarui vendor/producator de procesoare, fiecare putand sa-si organizeze procesorul cum doreste. Cea ce este comun mai multor vendori este macrocodul (sau setul de instructiuni al limbajului de asamblare/ISA)

.Spre exemplu, procesoarele pe arhitectura x86, gen Intel sau AMD, folosesc acelasi macrocod (set de instructiuni). De aceea un program compilat pentru un procesor Intel este portabil, putand fi executat si pe un procesor AMD.

Exemplu de instructiune:

add A, B

Daca A este registru, iar B este o zona din memorie, instructiunea se poate sparge in mai multe instructiuni de genul:

1. selecteaza registrul A din setul de registre al procesorului2. aduce valoarea din zona de memorie B in procesor3. aduna A cu B4. depune rezultatul in ADin punctul de vedere al programatorului, nu este de interes ce microcod executa in spate procesorul, atata timp cat obtine rezultatul dorit pentru macroinstructiunea care i-am dat-o.Daca, spre exemplu, la Intel se aduna A la B, iar la AMD se aduna B la A, acest

Page 5: Ce Este Limbajul de Asamblare

lucru nu deranjeaza atata timp cat are loc adunarea si depoziteaza ambele procesoare valoarea in acelasi loc. Totul este complet transparent pentru software.

Registre generale sunt cele care sunt folosite efectiv la calcule. In cazul nostru, ele sunt: AX, BX, CX, DX.Fiecare are 16 biti. Se poate accesa separat partea superioara si inferioara a fiecarui registru general.Se poate face acestul lucru folosind adresele xH si xL, unde x poate fi oricare din initialele registrilor mari (A - AX, B - BX, C - CX, D - DX).

Exemple de folosire a registrelor cu instructiunea add:

add AX, BX ; aduna AX cu BX si depune rezultatul in AX

add CH, DH ; aduna octetii superiori ai lui CX si DX, si depune rezultatul in CH

add BH, CL ; aduna octetul superior a lui BX cu octetul inferior a lui CX si depune rezultatul in BH

Exista un registru special, numit Flags, tot de 16biti, a carui biti au o semnificatie speciala.Fiecare bit este activat(set)/dezactivat(cleared) in functie de cum se termina operatia curenta.

Instructiunea add poate activa flagurile urmatoare:

overflow - cand rezultatul depaseste valoarea maxima (cu semn) reprezentabila in destinatie

carry - cand rezultatul depaseste valoarea maxima (fara semn) reprezentabila in destinatie

zero - daca rezultatul a dat zero.Flagul de carry ne poate ajuta sa adunam numere care depasesc marimea registrelor noastre, de exemplu numere pe 32biti. Este ca atunci cand faceam adunari in clasele primare:

"Adun 32 cu 8, vine 0, tin minte '1' care se aduna cu ce am mai la stanga, si vine 40".

Page 6: Ce Este Limbajul de Asamblare

In cazul de fata:

"Adun AX cu BX, tinem minte '1'(carry),

pe care il adaugam la partea superioara a numarului".

Flagul de zero (ZF) ne ajuta sa comparam 2 numere. 

Cand un procesor compara 2 numere, el de fapt le scade, iar daca rezultatul este zero (si flagul de zero este setat ca atare), inseamna ca sunt egale, altfel nu sunt egale.

Registre de stareBitii din registrul Flag sunt indicatori de stare care se pozitioneaza functie de rezultatul ultimei operatii aritmetice sau logice si se testeaza de instructiunile de salt.

Instructiunile de transfer a datelor si salt nu pozitioneaza indicatorii. O – Overflow flag depasire capacitate registru la operatii aritmeticeD – Direction flag directia deplasarii la instr. pe siruri de caractere( d=0 spre dreapta)I – Interupt enableflag intreruperi admiseT – Trap flagS – Sign flag indica semnul rezultatului (S=0 pozitiv, S=1 negativ)Z – Zero flag indica rezultat zero (Z=1)A – Auxiliar carry Transport intermediar din rangul 4 ( A=1)P - Parity flag Numar de biti par in rezultat (P=1)C – Carry flag Transport din rangul cel mai semnificativ (C=1)NT – Nested task Pentru control task-uri

…………………………………….

Aplicatiile in limbaj de asamblare vor fi scrise folosind setul de instructiuni al procesorului Intel 286, peste care rula in mod nativ sisteme de operare precum PC DOS, OS/2 si MS DOS. Cel din urma este simulat in mod partial de distributiile de Windows pe 32 de biti (nu si cele pe 64 de biti). Pentru alte distributii, se recomanda folosirea emulatorului DOSBox.Utilitarele folosite sunt:

Page 7: Ce Este Limbajul de Asamblare

Borland Turbo Assembler (TASM), pentru asamblarea fisierelor sursa (.asm sau .a) si crearea de fisiere obiect (.obj, .o, sau .elf)

Borland Turbo Linker (TLINK), pentru link-editarea fisierelor obiect si transformarea in executabile (.exe, .com)

Borland Turbo Debugger (TD) Utilitarul Debug.exe

TASM, TLINK si TD

Aceste utilitare, aduc urmatoarele functionalitati:

asamblarea fisierelor .asm, acceptand o sintaxa vag asemanatoare cu MASM, ce produce fisiere obiect .o. Exemplu: tasm file.asm

editarea de legaturi intre mai multe fisiere obiect, si crearea unui fisier executabil .exe. Exemplu: tlink file.o

executia pas-cu-pas a fisierului .exe. Exemplu: td file.exe

3.1. Descriere Debug

Debug este o aplicatie scrisa de Tim Paterson pentru sistemul de operare QDOS, spre a-l folosi ca utilitar de depanare a programelor. Odata cu mutarea sa la Microsoft, la inceputul anilor 80, programul a fost portat pe MS DOS si pe Microsoft Windows .Programul Debug, lansat dintr-o fereastra de comanda (“Command Prompt”) contine o serie de comenzi cu parametri valori in hexazecimal care permit accesul la resursele primare ale calculatorului:

locatii de memorie, registrele procesorului, porturi de intrare/iesire.

Debug este o aplicatie MS-DOS de depanare a programelor scrise in cod assembly.El are urmatoarele facilitati:

executarea pas cu pas a instructiunilor posibilitatea de a vedea valorile tuturor registrelor la un anumit pas din executie vizualizarea hartii de memorie introducerea de instructiuni noi in mijlocul executarii programului curent

Page 8: Ce Este Limbajul de Asamblare

Programul este prezent si pe toate versiunile curente de Windows pe 32 de biti (XP / Vista / Windows 7 / Windows 8).Pe celelalte variante de Windows puteti folosi DOSBox pentru a putea emula mediul MS-DOS, iar pe Linux se recomanda DOSEMU.

Comenzi Debug

Adresa unei zone de memorie este compusa din:

adresa_de_segment + deplasament

Consideram momentan doar deplasamentul din adresa, nu si adrese de segment.Toate valorile (adrese, valoare retinuta intr-o zona de memorie, etc.) sunt exprimate in cifre hexazecimale.

[] - parte optionala

adrI - adresa inceput

adrF - adresa finala

adrS - adresa segment

adr - adresa

reg - registru

C1, C2, C3... - constante

Numele comenzii

Modul de folosire

Comentarii

Page 9: Ce Este Limbajul de Asamblare

DUMP d [adrS:]adrI[, adrF]

Afiseaza continutul memoriei incepand cu adrI, si, optional, se poate spune si o adresa finalaadrF (pana unde poate merge).

FILL f [adrS:]adrI, adrF, [adrS:]adr, C1[, C2, C3…]

Umple zona de memorie cuprinsa intre adrI si adrF cu constantele C1, C2, C3…. Cand se ajunge la capatul sirului de constante, acesta se reia cu prima valoare.

ENTER e [adrS:]adr

QUIT q

COMPARE c [adrS:]adrI, adrF, [adrS:]adr

Compara element cu element vectorul de bytes delimitat de adresele adrI si adrF, cu vectorul care incepe la adr.

ASSEMBLE a [adrS:]adr Permite introducerea manuala a unui cod de asamblare direct din program, incepand cu adresa adr.

UNASSEMBLE u [adrS:]adr Afisaza codul de asamblare incepand cu adresa adr.

REGISTERS r reg Modifica valoarea registrul reg.

TRACE t pas Permite executarea instructiunilor unde a ajuns acum procesorul, afisand cate pas instructiuni, la fiecare apel.

MOVE m [adrS:]adrI, adrF, [adrS:]adr

Copiaza/muta valorile cuprinse intre adresele adrI si adrF la adresa adr.

SEARCH s [adrS:]adrI, adrF, C1[, C2, C3,…]

Cauta la adresele cuprinse intre adrI si adrF, constantele/valorile C1, C2, C3…

GO g [adrS:][adrI,] adrF

Executa toate instructiunile cuprinse intre adrI si adrF. Daca adrI lipseste, programul va executa instructiunile de unde a ramas procesorul, pana la adrF.

Page 10: Ce Este Limbajul de Asamblare

d<adr1>,<adr2> (“dump”) afiseaza continutul unei zone de memorie cuprinsa intre adresele adr1 si adr2.

f<adr1>,<adr2>,<lista_constante> (“fill”) umple zona de memorie cuprinsa intre adresele adr1 si adr2 cu lista de constante.

e<adr> (“enter”) permite introducerea unor valori de octeti incepand de la adresa adr. Trecerea la octetul urmator se face cu spatiu. Comanda se incheie cu <ENTER>.

q (“quit”) incheie programul Debug. c<adr1>,<adr2>,<adr3> (“compare”) compara zona de memorie cuprinsa

intre adresele adr1 si adr2 cu zona incepand de la adresa adr3. i<port> (“input”) citeste continutul portului specificat. o<port><octet> (“output”) inscrie octet la portul specificat. a<adr><ENTER>

…….instructiuni…..<ENTER> (“assemble”) permite introducerea si asamblarea unei secvente de instructiuni in limbaj de asamblare incepand cu adresa adr. Comanda se incheie cu instructiune vida <ENTER>.

u<adr> (“unassemble”) dezasambleaza continutul unei zone de memorie incepand de la adresa adr si afiseaza secventa de instructiuni sursa in limbaj de asamblare.

r (“registers”) afiseaza continuturile registrelor utilizator, accesibile prin program, si a registrului indicatori.

r<reg> afiseaza si permite modificarea registrului utilizator reg. t<nr_instr> (“trace”) executa numarul de instructiuni nr_instr de la valoarea

curenta a contorului de instructiuni IP. m<adr1>,<adr2>,<adr3> (“move”) muta zona de memorie cuprinsa intre

adresele adr1 si adr2 in noua zona incepand de la adresa adr3. s<adr1>,<adr2>,<lista_oct> (“search”) cauta lista de octeti in zona cuprinsa

intre adresele adr1 si adr2. g=<adr1>,<adr2> (“go”) lanseaza in executie codul aflat in memorie incepand

de la adresa adr1 pana la adresa adr2 (“breakpoint” - punct de suspendare a executiei programului). Daca adr1 lipseste (lipseste si caracterul '=') executia este lansata de la adresa curenta a contorului de program IP, pana la adresa adr2.

Mesaje de eroare:

bf = s-au tastat caractere greşite pentru indicatorii de condiţii (bad flag) bp = s-au specificat prea multe puncte de breakpoint într-o comandă G (too

many breakpoints) br = nume gresit de registru (bad register)

Page 11: Ce Este Limbajul de Asamblare

df = s-au specificat două valori diferite pentru acelaşi indicator (double flag)Restrictiile Debug sunt urmatoarele:

toate adresele sunt absolute toate constantele sunt absolute si hexazecimale nu se pot utiliza nume symbolic

Exercitii:

1. Sa se afiseze continutul zonei de memorie cuprinsa intre adresele 100-13F.

Metoda de rezolvare: Dump.Cod:

d100,13f

2. Sa se umple zona de memorie 100-13F cu valoarea constanta 55 si sa se verifice operatia.

Metoda de rezolvare: Fill.Cod:

f100,13f,55

d100,13f

3. Sa se introduca in fiecare locatie din zona 100-13F o valoare reprezentata de ultimii 8 biti de adresa a locatiei respective (00, 01, 02, …) si sa se verifice.

Metoda de rezolvare: Enter, cu introducerea manuala a datelor.Cod:

e100

00 [spatiu] 01 [spatiu] ... 3F [enter]

Page 12: Ce Este Limbajul de Asamblare

d100,13f

4. Sa se mute zona de memorie precedenta in zona cuprinsa intre adresele 300-33F.

Metoda de rezolvare: Move.

Cod:

m100,13f,300

5. Sa se compare zona de memorie 100-13F cu zona 200-23F si apoi cu zona 300-33F.

Metoda de rezolvare: Compare.Cod:

c100,13f,200

c100,13f,300

6. Sa se caute octetii 0F, 1F, 2F si 3F in zona de memorie 100-33F.

Metoda de rezolvare: Search.Cod:

s100,33f,0f

s100,33f,1f

s100,33f,2f

s100,33f,3f

7. Sa se afiseze si sa se modifice continuturile registrelor utilizator.

Page 13: Ce Este Limbajul de Asamblare

Metoda de rezolvare: Register. Comanda r afiseaza continutul registrelor,iar r scris impreuna cu un registru ii modifica valoarea.Cod:

r

rES

52

8. Sa se introduca o secventa de program in limbaj de asamblare incepand de la adresa 300 si sa se execute secventa respectiva urmarind modificarea registrelor utilizator.

Mod de rezolvare: Asamblarea se face cu comanda a. Introducem spre exemplu comanda inc ax, care incrementeaza valoarea deja prezenta in acel registru, simov, care atribuie registrului bx valoarea 200.Cod:

a300

inc ax

mov bx,200 [2 enteruri]

g=300,304

9. Sa se execute secventa precedenta de program instructiune cu instructiune, urmarind modificarea registrelor.

Metoda folosita: Trace.Cod:

t

Page 14: Ce Este Limbajul de Asamblare

10. Sa se dezasambleze continutul zonei de memorie de la punctul precedent, precum si continutul zonei cuprinse intre adresele 200-23F.

Metoda folosita: Unassemble.Cod:

u300

u200,23f

Tutorialul 5. Adresarea memoriei. Segmentare.

Materiale necesare:

niciunulIn acest tutorial, dupa o mica introducere, vom incepe efectiv sa scriem cod.Pentru inceput, vom completa setul registrelor generale ale unui procesor 286.

Registre generale

Rol special

AX (AH) (AL) Registru acumulator

BX (BH) (BL) Registru baza

CX (CH) (CL) Registru numarator (counter)

DX (DH) (DL) Registru de date

BP Registru baza

SI Registru index

DI Registru index

SP Indicator stiva

Page 15: Ce Este Limbajul de Asamblare

Cu ajutorul primelor 4 se pot face aproape orice operatii aritmetice si orice operatii pe biti.Vom vorbi imediat despre rolurile registrelor baza si a registrelor index.Registrul CX ne ajuta sa construim un echivalent al structurilor for din limbajul C, iar despre SP vom vorbi mai tarziu.Rolul registrului AX tine mai mult de o conventie. Functiile limbajului C, traduse in limbaje de asamblare, folosesc registrul AX pentru a intoarce rezultatul functiei.Aceasta valoare poate fi un tip standard (int, char, float, etc.) sau, in cazul structurilor, poate fi un pointer (adresa) catre structura rezultata.

Adresarea memoriei

Exemplu de declarare a unor date:

x DB 47 ; am declarat o variabila 'x' de tip "char" cu valoarea initiala 47

y DB 1, 2, 3, 4, 5 ; am declarat un fel de vector de char-uri care contine elementele {1, 2, 3, 4, 5}

Pentru a accesa variabila x:

add AH, x ; adauga valoare lui x la continutul registrului AH

Pentru a accesa primul element din y:

add AH, y ; adauga valoarea primului element din y

Pentru a accesa zone de memorii mai complexe (gen al n-lea element din y) ne folosim de operatorul de dereferentiere:

[]

Acesta actioneaza aproximativ ca * din C. Adica i se da o zona de memorie si el iti intoarce ce gaseste la zona aia de memorie.Exemplu:

Page 16: Ce Este Limbajul de Asamblare

mov BX, offset x ; muta in registrul BX, adresa lui x

add AH, [BX] ; adu valoarea spre care pointeaza BX si adun-o la AH

offset se comporta oarecum ca operatorul & din C

Cu acest operator putem accesa si elementele dintr-un vector, dar folosind mai multe “variabile” pentru a ajunge la acea zona de memorie.O adresa poate fi compusa din 3 elemente:

[registru_baza + deplasamanet + registru_index]

Registre baza: BX, BPDeplasament: orice adresa imediata a unei zone de memorie (o constanta)Registre index: SI, DIAstfel, pentru a accesa un element din vectorul y:

mov BX, offset y

add AH, [BX+2] ; acceseaza elementul al 3-lea din vector (ca si in C, prima adresa/element dintr-un vector este la indexul 0)

Nu puteti combina 2 registri baza, sau 2 registri index.

In caz ca vrem sa fim mai dinamici si sa iteram prin vector, putem folosi un registru baza si un registru index:

mov BX, offset y

mov SI, 0

add AH, [BX+SI] ; AH = AH + y[0]

add SI, 1 ; SI++

Page 17: Ce Este Limbajul de Asamblare

add AH, [BX+SI] ; AH = AH + y[1]

Acest lucru o sa inceapa sa ne foloseasca cand vom invata sa lucram cu bucle, asemanatoare while sau for din C.

Segmentare

Registre segment Denumire completa

CS Code Segment

DS Data Segment

ES Extra Segment

SS Stack Segment

Registre de stare si control

Denumire completa

IP Instruction Pointer

F Flags

MSW Machine Status Word

La ce folosesc registrele segment ?

Procesorul 286 are registre de 16 biti. Registrele cu care se poate face adresare (BX, SI, DI, etc.) sunt de 16biti.Din aceasta cauza putem adresa doar 216 (64K) bytes in interiorul unui segment.Pentru mult timp asta era perfect ok, dar apoi au aparut memorii mai mari de 64K, si era nevoie de un mod de a le accesa.Se poate face acesta cu ajutorul segmentelor.Propriu-zis, cand accesam o zona de memorie, adresarea se face relativ la un segment.Adresa unei zone de memorii este compusa din:

adresa_de_segment + deplasament

Page 18: Ce Este Limbajul de Asamblare

Mai exact, ele se aduna asa:

registru segment xxxx

xxxx xxxx xxxx

deplasament xxxx xxxx xxxx

xxxx

Unde x sunt biti. In general, nu se va pune problema cum se ajunge la adresa efectiva, si doar ca registrul segmentului este cel dorit.

Procesorul a fost gandit sa foloseasca 3 segmente principale:

un segment pentru date un segment pentru cod un segment pentru stiva De aceea exista registrele: DS, CS, SS. Prima initiala vine de la tipul segmentului, iar a doua initiala vine de la segment.Mai exista un segment ES (extra segment) care este folosit, in general, la lucrul pe siruri.Poate vrem sa copiem dintr-o zona de memorie in alta, dar intre cele doua zone de memorie este o distanta mai mare de 64K (adica se afla insegmente de memorie diferite).Astfel, in loc sa schimbam mereu continutul lui DS (si sa mai folosim si alte instructiuni intermediare), putem folosi segmentul “extra”.

Ce se intampla in spate ?

De fiecare data cand accesam o zona de memorie, TASM considera ca folosim un registru segment implicit.Exemplu:

add ax, x

este de fapt, in spate:

Page 19: Ce Este Limbajul de Asamblare

add ax, ds:x ; pentru ca x este o variabila => se va regasi in **zona(segmentul)** de date.

Aceste variante sunt echivalente, asamblorul le va accepta pe amandoua.

Segmente de memorie vs registre segmente

In assembly, by default, exista 3 segmente principale, cele mentionate mai sus (cod, date, stack). Registrele segment retin adresa acestor segmente.

Segmentul de date

Segmentul de cod

Procesorul se foloseste de registrele CS si IP (instruction pointer) pentru a sti ce instructiune urmeaza sa execute.Executarea unei instructiuni are urmatorul ciclu:

1. se incarca instructiunea de la adresa CS:IP2. se executa instructiunea3. se incrementeaza registrul IPIP se mai poate modifica prin instructiuni de tip jump care, dupa cum spune si numele tipului lor, fac procesorul sa sara la alta zona de memorie.

Segmentul de stiva

Stiva este o implementare a structurii de date clasice care este invatata la SD.Ea este folosita pentru a stoca variabile intermediare in program (de exemplu cand nu mai avem un registru liber) si pentru a putea face apelul unei proceduri.Cand o procedura este apelata, i se depune pe stiva adresa de intoarcere, astfel ca atunci cand se ajunge la finalul functiei, programul isi ia adresa de intoarcere de pe stiva.Stiva este implementata ca un vector, a carui elemente se adauga incepand de la

Page 20: Ce Este Limbajul de Asamblare

coada.Ca sa se inteleaga mai usor, uitati cum este vazuta memoria in general:

64

63

62

2

1

0

Segmentul de stiva arata cam asa:

capatul_vectorului(stivei)

valoare_depusa_pe_stiva

unde_indica_SP

spatiu_liber

unde_indica_SS

Ca orice segment, adresa lui este retinuta intr-un registru specific (SS - stack segment), si are un pointer pentru a arata deplasamentul fata de adresa de

Page 21: Ce Este Limbajul de Asamblare

baza/segment: registrul SP (stack pointer).Sa zicem ca ii spunem asamblorului ca vrem un segment de stiva de 16 bytes ⇒ vom avea un vector, sa-l numim simplu stiva, de 16 elemente.

byte stiva[16];

short SP = sizeof(stiva);

Cand se face un push se intampla urmatorul lucru:

SP--; stiva[SP] = element_depus;La pop:

variabila = stiva[SP]; SP++;

 Reprezentari numerice.

Procesoarele au 2 tipuri principale de reprezentare a numerelor in memorie:

big endian: cel mai semnificativ byte este cel mai din stanga. little endian: cel mai semnificativ byte este cel mai din dreapta.

Procesoarele Intel sunt de tip little endian.

Bitii per byte nu sunt inversati la little endian.

Exista procesoare, precum Power PC, care folosesc big endian. De asemenea echipamentele din retea si protocoalele de retea reprezinta numerele in stil big endian.

Acest aspect tine de reprezentarea in memorie. Si procesoarele Intel, dupa ce citestc datele din memorie, folosesc pentru operatii reprezentarea big endian (aka in registre vor fi tot in big endian).

Page 22: Ce Este Limbajul de Asamblare

Reprezentarea numerelor negative

Intr-o data ce ocupa n biti, putem stoca 2n valori posibile. Alternativ, daca avem nevoie sa stocam nnumere intr-un tip de data, latimea acestuia trebuie sa fie de minim [log2(n)] + 1 biti.

Desi multimea valorilor posibile ale unui numar pe n biti este aceeasi (formata din aceleasi 2n elemente), multimea interpretarilor acestor numere difera. Astfel avem:

cod binar: interpretarea sirului de cifre binare este chiar pozitia lui intr-o ordonare lexicografica. Exemplu: 0010 0010(2) = 22(16) = 34(10). cod direct: primul (cel mai semnificativ) bit este tratat ca bit de semn, iar

urmatorii biti sunt tratati, ca la codul binar uzual, ca biti de date. cod complementar

complement fata de 1: bitii de date sunt inversati fata de codul direct complement fata de 2: obtinut adunand 1 la complementul fata de 1.

cod zecimal: BCD impachetat BCD neimpachetat

Bitul de semn

Exista doua tipuri de numere intregi: signed si unsigned.Numerele signed folosesc primul bit pentru semn.Sa vedem cum arata un numar negativ, reprezentat in fiecare din aceste codificari.

Cod direct

In codul direct, asa cum spuneam, nu ne intereseaza decat bitul de semn, iar bitii de date vor corespunde valorii absolute a numarului.Spre exemplu, numarul -5, reprezentat pe 8 biti in cod direct, este 1000 0101.

avantaje: reprezentare foarte usoara pentru numere de la -127 la +127.

dezavantaje: numarul zero are doua reprezentari: 0000 0000 si 1000 0000. pentru operatii aritmetice, avem nevoie de:

detectia semnului transformarea numerelor negative in pozitive stabilirea semnului rezultatului aritmetica efectuata cu un sumator sau un scazator in cod direct, dupa caz

Page 23: Ce Este Limbajul de Asamblare

Bits Unsigned value Direct code value

0111 1111

127 127

0111 1110

126 126

0111 1101

125 125

0111 1100

124 124

… … …

0000 0000

0 0

1000 0000

128 0

1000 0001

129 -1

1000 0010

130 -2

… … …

1111 1100

252 -124

1111 1101

253 -125

Page 24: Ce Este Limbajul de Asamblare

1111 1110

254 -126

1111 1111

255 -127

Complement fata de 1

Fata de codul direct, in complementul fata de 1, bitii de date sunt inversati. Astfel, pentru a reprezenta numarul -5 pe 8 biti, am scrie 1111 1010.De notat ca nu am obtinut niciun avantaj sau dezavantaj fata de codul direct.Sa vedem cum arata, totusi, reprezentarea numerelor pe 8 biti:

Bits Unsigned value One's complement value

0111 1111 127 127

0111 1110 126 126

0111 1101 125 125

0111 1100 124 124

… … …

0000 0000 0 0

1111 1111 255 0

1111 1110 254 -1

1111 1101 253 -2

… … …

1000 0011 131 -124

1000 0010 130 -125

Page 25: Ce Este Limbajul de Asamblare

1000 0001 129 -126

1000 0000 128 -127

Complement fata de 2

Fata de metodele de reprezentare prezentate mai sus, complementul fata de 2 prezinta urmatoarele avantaje:

reprezentare unica pentru 0 aritmetica unificata pentru numere negative si pozitiveSa zicem ca vrem sa reprezentam numarul -5.Pentru a face asta urmam acesti pasi:

1. reprezentam numarul in binar2. negam pe biti numarul.3. adaugam 1 la rezultat.Care se traduce in:

1. 0000 0101(2) = 5(10)

2. 1111 1010(2) = 250(10, unsigned) = -6(10, signed)

3. 1111 1011(2) = 251(10, unsigned) = -5(10, signed)

exemplu 37, la numarul -2.

1111 1110 +

0010 0101

(1)

0010 0011

Am efectuat adunarea ca pentru doua numere obisnuite, fara semn. Putem observa ca am obtinut numarul 35, adica cel corect (37 - 2), si valoarea 1 in carry, pe care o putem ignora.

Sa vedem de ce complementul fata de 2 functioneaza:

Stim ca x + (-x) = 0.De asemenea, fiindca lucram pe un numar limitat de biti (sa spunem n), toate

Page 26: Ce Este Limbajul de Asamblare

operatiile noastre vor fi modulo 2n.Sa vedem ce obtinem atunci cand adunam un numar cu complementul sau fata de 1:

1001 0111 +

0110 1000

1111 1111

Asadar, rezultatul este intotdeauna 1 pe toti bitii, deoarece adunam fiecare bit cu complementul lui.Daca am aduna 1 la aceasta valoare, am obtine primul numar nereprezentabil pe n biti, care s-artrunchia la zero, si ar genera carry.Acum, adunand 1 la rezultat, am gasit un numar care, prin adunare cu numarul nostru original, da zero, modulo 2n.De aceea, in complement fata de 2, -x = ¬x + 1.

BCD neimpachetat

Pentru o tratare mai amanuntita a acestui subiect, recomandam citirea acestui tutorial.

BCD: Numele acestui format spune ca numarul va fi reprezentat in format zecimal, fiecare cifra zecimala avand byte-ul ei.De exemplu, reprezentam numarul 96:

format binar: 0110 0000 format BCD neimpachetat: 0000 1001 0000 0110Pe primul byte la BCD este cifra 9, iar pe al doilea byte este cifra 6.

BCD impachetat

Dupa cum spune si numele, formatul este impachetat ⇒ adica fiecare cifra zecimala se regaseste pe cate o tetrada/nyble (4biti, jumate dintr-un byte).Exemplu:

format binar: 0110 0000

format BCD neimpachetat: 0000 1001 0000 0110

Page 27: Ce Este Limbajul de Asamblare

format BCD impachetat: 1001 0110

In formatul neimpachetat pierdem la fiecare cifra cate jumate de byte.

Formatul BCD nu mai este popular, insa era folosit la panourile de afisaje. Numerele se pot afisa rapid in acest format, pentru ca nu este nevoie de multe instructiuni intermediare pentru afisarea fiecarei cifre.In formatul BCD este nevoie doar de o adunare pentru a aduce cifra la forma ei ASCII.

Virgula fixa si virgula mobila

Daca la reprezentarea numerelor intregi, fiecare bit reprezinta o putere crescatoare a lui 2, la numere in virgula fixa, tot ce este dupa virgula, este o putere negativa a lui 2.

… 23 22 21 20 2-1 2-2 2-3 …

… 8 4 2 1 1/2 1/4 1/8 …

… 8 4 2 1 0,5 0,25

0,125 …

Numarul 2,75 se poate reprezenta in virgula fixa astfel:

0000 0010 , 1100 0000

Insa la acest format a numerelor reale se risipesc multe reprezentari.De exemplu, la acest numar, la care folosim 16biti, primul si ultimul nyble nu este folosit deloc.De aceea o organizatie a dezvolat un format standard de reprezentare a numerelor reale in virgula mobila care ofera cat mai multe reprezentari pe un anumit numar de biti.Organizatia se numeste IEEE, iar standardul se numeste IEEE 754.

Page 28: Ce Este Limbajul de Asamblare

BCD ( Binary Coded Decimal).

Putem beneficia de reprezentarea usoara a numerelor, pe care o ofera sistemul hexazecimal, insa toate operatiile aritmetice s-ar face conform regulilor zecimale folosind BCD

1. Reprezentare

Avem 16 cifre, numerotate de la 0 la 9 si de la A la F, ce corespund urmatoarelor valori:

Binar

Zecimal Hexazecimal

0000 0 0

0001 1 1

0010 2 2

0011 3 3

0100 4 4

0101 5 5

0110 6 6

0111 7 7

1000 8 8

1001 9 9

1010 10 A

1011 11 B

1100 12 C

Page 29: Ce Este Limbajul de Asamblare

1101 13 D

1110 14 E

1111 15 F

Algoritmul “clasic” de determinare a cifrelor intr-o noua baza: se executa impartiri repetate la baza b(pana cand catul ajunge zero), si se salveaza resturile obtinute. In final, resturile sunt afisate in ordine inversa.

mov AX, numar

xor DX, DX ; DX:AX = numar

mov BX, baza

mov CX, 0

 

_bucla:

div BX

push DX

xor DX, DX

inc CX

test AX, AX

jnz _bucla

Majoritatea microprocesoarelor nu au o unitate hardware dedicata instructiunii de impartire (div), fiindca aceasta este extrem de complexa si ar ocupa o portiune considerabila de siliciu. In speta, Intel 8086 se bazeaza pe o implementare software, in microcod2), a acestei instructiuni. Ca dezavantaj, pe

Page 30: Ce Este Limbajul de Asamblare

acest procesor, o instructiune div dureaza intre 200 si 300 de cicli de ceas. Luand in considerare si exceptiile ce pot aparea3), latenta pentru calculul unei impartiri la o baza constanta este extrem de mare.Baza hexazecimala beneficiaza de faptul ca 16 = 24. Astfel, impartirea si restul pot fi obtinute extrem de usor, folosind operatii pe biti:

restul impartirii la 16 sunt ultimii (cei mai nesemnificativi) 4 biti impartirea se realizeaza shiftand numarul la dreapta cu 4 biti

mov AX, numar

 

_bucla:

mov DX, AX

and DX, 0Fh

push DX

shr AX, 4

jnz _bucla

Astfel, daca am supradefini cifrele BCD peste primele 10 cifre hexazecimale, am putea beneficia de avantajul prezentat mai sus:

Binar BCD

0000 0

0001 1

0010 2

0011 3

Page 31: Ce Este Limbajul de Asamblare

0100 4

0101 5

0110 6

0111 7

1000 8

1001 9

Remarcam ca din cele 24 = 16 codificari disponibile pe 4 biti, noi am folosit doar 10. Astfel, pretul pe care il platim este ca avem o eficienta de 62,5% in reprezentare.In memorie, exista mai multe moduri de a stoca un numar in cod BCD:

2. BCD impachetat

In acest mod de reprezentare, fiecare cifra zecimala ocupa o tetrada/nibble (4 biti). Asadar, indiferent de numarul de octeti pe care avem reprezentarea, numarul cifrelor BCD este unul par (avem doua intr-un octet).

In cod binar, intr-un octet putem reprezenta 28 = 256 valori posibile, fie ele unsigned (0 → 255) sau signed (-128 → 127).

In cod BCD impachetat, intr-un octet putem reprezenta valori de la 00 la 99, asadar 100 de valori. Eficienta este, de data aceasta, de39.06% (62.5%2, caci avem 2 cifre).

Observam ca eficienta scade exponential cu cat numarul de octeti ai reprezentarii creste.Spre exemplu, pe 4 octeti (32 de biti), putem avea 4.294.967.296 valori binare, si 100.000.000 de valori BCD impachetat, conducand la o eficienta de 2.32%!O formula generala pentru eficienta reprezentarii pe n octeti poate fi data astfel:η = 102n / 28n

Ca avantaj al acestei scrieri, toate numerele BCD se suprapun peste codificari hexazecimale deja existente:28(BCD) = 28(16) = 0010 1000(2)

3. BCD neimpachetat

Page 32: Ce Este Limbajul de Asamblare

In aceasta forma de codificare, intotdeauna tetrada superioada a unui octet este goala. Astfel, un octet poate stoca o cifra BCD numai in tetrada sa inferioara.

Eficienta in reprezentare este extrem de scazuta: 10/256 = 3.9%, pentru un singur octet! Ea scade dupa o formula asemanatoare cu cea de la impachetat:η = 10n / 28n

O variatiune a acestei codificari este codul ASCII pentru caracterele 0 → 9. Pentru acesta, tetrada superioada are valoarea 0011(2) = 3(16) = 3(BCD). Din acest motiv, o conversie intre BCD neimpachetat si ASCII este foarte usoara: trebuie fie sa adunam, fie sa scadem valoarea 30(16).

Zecimal BCD neimpachetat ASCII

0 0000 0000 0011 0000

1 0000 0001 0011 0001

2 0000 0010 0011 0010

3 0000 0011 0011 0011

4 0000 0100 0011 0100

5 0000 0101 0011 0101

6 0000 0110 0011 0110

7 0000 0111 0011 0111

8 0000 1000 0011 1000

9 0000 1001 0011 1001

4. Operatii aritmetice cu BCD

4.1. Adunare cu BCD impachetat

Deducem, din modul de reprezentare BCD impachetat, ca putem scrie, spre exemplu, in registrul AL valoarea hexazecimala 78h, insa sa ne gandim la ea ca la numarul zecimal 78d.

Page 33: Ce Este Limbajul de Asamblare

78(16) = 78(BCD).78(10) = 4E(16)!!!

Un sistem de reprezentare este inutil, daca el nu permite si o serie de operatii aritmetice si logice inchise asupra lui4).Din pacate, vom vedea ca operatiile aritmetice uzuale nu sunt inchise in raport cu reprezentarea noastra BCD.

I) Sa consideram urmatorul exemplu, in care am adunat doua numere BCD (deci si hexazecimale), si am obtinut un numar hexazecimal, insa care nu este BCD:

37(16) + 45(16) = 7C(16)

37(BCD) + 45(BCD) = 82(BCD)

Pentru a realiza corect operatia de adunare in BCD, trebuie sa intelegem intai motivul pentru care ea nu functioneaza corect in forma actuala:

In zecimal, daca rezultatul unei adunari este mai mare decat 9, se va genera un transport care se propaga catre rangul urmator al numarului.

In hexazecimal, transportul se propaga abia daca rezultatul este mai mare decat 15. Pentru valori cuprinse intre 10 si 15, rezultatul va fi o cifra hexazecimala intre A si F, cifra care nu este definita pentru BCD.

Cu aceste considerente in minte, daca reusim sa depistam executia gresita a unei adunari BCD, trebuie doar sa fortam propagarea transportului in mod corect catre rangul urmator, in baza 16. Putem obtine acest lucru, adaugand 6 la rezultat (16 - 10).

7C(16) + 6(16) = 82(16) = 82(BCD)

II) Sa mai tratam si alte cazuri posibile:

19(16) + 28(16) = 41(16)

41(16) + 6(16) = 47(16) = 47(BCD)

De notat ca acest caz este relevant, nu din cauza ca avem vreo cifra cuprinsa intre A si F, ca in cazul precedent, ci pentru ca adunarea 9(16) + 8(16) = 11(16) a generat un transport dinspre prima cifra spre a doua. Numim acest transport AF5)

III) Desigur, putem avea fix aceleasi situatii de depasire si pentru cifra superioara a numarului:

81(16) + 24(16) = A5(16)

A5(16) + 60(16) = 105(16)

Page 34: Ce Este Limbajul de Asamblare

In aceasta situatie, cifra superioara este intre A si F, deci trebuie sa adaugam 60(16) pentru a o corecta. In urma adunarii nu mai putem tine intreg rezultatul in memorie, deoarece formatul BCD impachetat permite stocarea a doua cifre, iar rezultatul (105) incape pe 3. Din acest motiv, trebuie sa trunchiem rezultatul la ultimele doua cifre (05) si sa declansam flagul de carry (CF = 1).

IV) Inca o situatie este cea in care cifra superioara nu este cuprinsa intre A si F, insa tot a avut loc o depasire:

95(16) + 92(16) = 127(16) → 27(16) si CF = 1 27(16) + 60(16) = 87(16)

V) Trebuie sa avem mare atentie si la cazul in care depasirea este produsa de cifra mai putin semnificativa, insa carry-ul se propaga si prin cea mai semnificativa:

55(16) + 47(16) = 9C(16)

9C(16) + 6(16) = A2(16)

A2(16) + 60(16) = 102(16) → 0216 si CF = 1Comportamentul de mai sus este sintetizat de instructiunea daa6). Ea este un fel de pilula de a doua zi, in sensul ca se foloseste pentru corectia la BCD a unei adunari hexazecimale, ce a avut rezultatul in AL.

OldCF = CF;

OldAF = AF;

 

/* Corectam rezultatul pentru cifra mai putin semnificativa.

Aici se afla situatiile I, II si V */

if (AL & 0xF > 9 || AF == 1) {

CF = OldCF | GetCarry(AL = AL + 6);

AF = 1;

} else {

Page 35: Ce Este Limbajul de Asamblare

AF = 0;

}

 

/* Corectam rezultatul pentru cifra mai semnificativa.

Daca a aparut un transport aici, trebuie sa activam

neconditionat carry-ul global.

Aici se incadreaza situatiile III si IV */

if (OldAL > 0x99 || OldCF == 1) {

AL = AL + 0x60;

CF = 1;

} else {

CF = 0;

}

4.2. Scadere cu BCD impachetat

Aceleasi situatii ca la adunare pot aparea si la scadere. Sa vedem un caz in care operatia se desfasoara corect:

34(16) - 12(16) = 22(16).Acum sa tratam celelalte cazuri posibile:I) Scaderea cifrelor mai putin semnificative genereaza imprumut (AF = 1), iar rezultatul este cuprins intre A si F:

34(16) - 15(16) = 1F(16). 1F(16) - 6(16) = 19(16).

Page 36: Ce Este Limbajul de Asamblare

II) Scaderea cifrelor mai putin semnificative genereaza imprumut (AF = 1), dar rezultatul este o cifra cuprinsa intre 0 si 9:

30(16) - 19(16) = 17(16). 17(16) - 6(16) = 11(16).III) Scaderea cifrelor semnificative genereaza imprumut (CF = 1), iar rezultatul este cuprins intre A si F:

15(16) - 21(16) = F4(16). F4(16) - 60(16) = 104(16) → 04(16), CF = 1.IV) Scaderea cifrelor semnificative genereaza imprumut (CF = 1), iar rezultatul este cuprins intre 0 si 9:

15(16) - 81(16) = 94(16). 94(16) - 60(16) = 34(16). CF trebuie setat pe 1, iar 34 semnifica -66 (100 - 34).V) Scaderea cifrelor mai putin semnificative genereaza imprumut, care se propaga si prin scaderea cifrelor semnificative:

21(16) - 23(16): (1)1(16) - 3(16) = E(16), AF = 1. 2(16) - 2(16) - 1(16)(AF) = F(16), CF = 1.

Cele 5 cazuri prezentate mai sus pot fi rezumate de codul urmator, al instructiunii das7):

OldAL = AL;

OldCF = CF;

CF = 0;

 

if(AL & 0xF > 9 || AF == 1) {

CF = OldCF | GetBorrow(AL = AL - 6);

AF = 1;

Page 37: Ce Este Limbajul de Asamblare

} else {

AF = 0;

}

 

if(OldAL > 0x99 || OldCF == 1) {

AL = AL - 0x60;

CF = 1;

} else {

CF = 0;

}

4.3. Alte operatii

In mod similar, exista instructiuni de corectie si in cazul numerelor zecimal neimpachetate, cu deosebirea ca logica acestora este mai simpla.In cazul adunarii, rezultatul nu poate fi decat cel mult 9(16) + 9(16) = 12(16) → 02(BCD), si CF = 1. Corectia rezultatului este realizata de instructiunea aaa8).La scadere, avem de tratat o situatie asemanatoare, cand scadem dintr-un numar mai mic un numar mai mare - altfel, ea nu genereaza probleme. Instructiunea este aas9).

Numai pentru BCD neimpachetat, mai avem doua operatii:I) aam10) este o instructiune de 2 octeti, ce imparte registrul AL la 10, si pune restul in AL si catul in AH.

09(16) * 09(16) = 51(16) = 81(10) (AL). 51(16) / 0A(16) = 08(16) (AH), % 0A(16) = 01(16) (AL).

Page 38: Ce Este Limbajul de Asamblare

Instructiunea AAM nu a fost documentata de Intel pana la seria de procesoare Pentium, desi a fost prezenta pe toate modelele, de la 8086. Ea ofera mai multe lucruri pe care instructiunea normala divnu le ofera:

Realizeaza o impartire octet la octet - div nu permite decat word la octet. Pe langa forma fara parametri, accepta si un operand de 8 biti, ce reprezinta

deimpartitul. Exemplu: aam 16. Setarea flagurile in functie de rezultat.II) aad11), la fel ca si aam, este nedocumentata, si ofera o alternativa la mul cu un operand de 8 biti. Baza implicita (in caz ca nu este specificata in instructiune) este 10. Ea functioneaza in felul urmator:

AL ← (AH * baza) + AL. AH ← 0.Exemplu: Fie un numar in format BCD neimpachetat, AX = 0703h, deci AX = 73(BCD).

AL ← 7 * 10 + 3 ⇒ AL ← 73(10)

AH ← 0.Asadar, in urma aplicarii operatiei, am convertit numarul BCD neimpachetat 0703h in numarul zecimal (sau binar, caci au aceeasi forma de reprezentare) 73(10).Daca am executa operatia:

mov AX, 0703h

aad 16

Atunci in AL vom obtine numarul convertit la BCD impachetat.

Interesting links:AAM.

Page 39: Ce Este Limbajul de Asamblare

Sa luam un exemplu:

numarul 2,75

Forma binara in virgula fixa:

10.11

Forma IEEE 754 pe 32biti:

0 1000 0000 011 0000 0000 0000 0000 0000

Page 40: Ce Este Limbajul de Asamblare

0 128 xxx

2,75 = mantisa * 2exponent = 1.011 * 2(128-127) = 1.011(binar) * 21(zecimal) = 10.11

Pasi urmati:

1. se reprezinta numarul in virgula fixa2. se shifteaza la dreapta (se imparte la 2) pana cand singurul bit dinainte de

virgula este cel mai semnificativ3. acum numarul = mantisa(numarul rezultat dupa shiftare) * 2exponent(numar shiftari)

4. primul bit din mantisa stim mereu ca este setat pe 1 pentru ca este cel mai semnificativ ⇒ nu-l mai reprezentam ⇒ mai castigam un bit pentru reprezentarea mantisei

5. toti bitii exponentului setati pe 1 sau 0 au semnificatie speciala asa ca folosim un deplasament (adunam 127 la valoarea exponentului).

Acum avem tot numarul reprezentat: bitul de semn, exponentul si mantisaCazuri speciale:

Number Sign

Exponent Fraction

0 x 00000000 00000000000000000000000

+ ∞ 0 11111111 00000000000000000000000

- ∞ 1 11111111 00000000000000000000000

Not a number x 11111111 non-zero