ARCHITEKTURA KOMPUTERÓW - LABORATORIUM Program hybrydowy Dokumentacja ćw. 1-4 Zuzanna Hartleb i Artur Angiel 2010-06-16
Działanie Program pobiera od użytkownika liczbę zmiennoprzecinkową, sprawdza poprawnośd wprowadzonych danych i konwertuje ją na postad obliczeniową. Otrzymana zmienna typu double jest następnie wyświetlana w postaci binarnej, z podziałem na znak, cechę i mantysę. Struktura... jest programem o strukturze hybrydowej. Składa się z następujących modułów: main.cpp modułu w języku c++, odpowiedzialnego za pobieranie danych, sprawdzanie ich poprawności i wyprowadzanie wyniku; lib.asm modułu asemblerowego, w którym znajduje się procedura konwersji łaocucha znakowego na postad obliczeniową; makra.asm pliku z użytymi w module asemblerowym makrami. Łączenie modułów Projekt składający się z dwóch modułów, włącznie z modułem asemblerowym, został zbudowany przy użycia środowiska Turbo C++ 3.0 firmy Borland. W tym celu użyto polecenia: tcc main lib.asm Wszystkie argumenty przekazano do funkcji asemblerowej, zgodnie z konwencją języka C, to znaczy przez stos. To znaczy, w module C++ wykonano przypisanie: double wynik = Przelicz(napis, licznik); A następnie parametry pobrano ze stosu przy pomocy makra PobierzBufor: PobierzBufor MACRO push bp mov bp, sp push cx push si push di mov si, [bp+4] mov cx, [bp+6] mov di, offset Bufor rep movsb pop di pop si pop cx pop bp ENDM mov byte ptr [di], '$' Ćwiczenie 1-4 Strona 2
Liczba w postaci obliczeniowej zostaje odłożona na stosie koprocesora, skąd jest automatycznie pobierana przy zakooczeniu funkcji. RAMKA STOSU Jest to obszar stosu przeznaczony na parametry wywołania procedury oraz jej zmienne lokalne; przechowuje także adres powrotu z procedury oraz odłożoną oryginalną zawartośd rejestru bazowego. Sprawdzanie poprawności wprowadzonego łańcucha Sprawdzanie poprawności, dla ułatwienia, zrealizowano w module języka C++. if(napis[licznik] == '-'){licznik++; jeżeli pierwszym znakiem jest minus, zostaje on pominięty if(napis[licznik] < '0' napis[licznik] > '9'){ return -1; sprawdzenie czy na pierwszej pozycji jest cyfra licznik++; pętla, w której sprawdzana jest poprawność kolejnych znaków while(napis[licznik]!= '\0'){ if(napis[licznik] >= '0' && napis[licznik] <= '9'){ licznik++; else{ switch(napis[licznik]){ case '.': if(kropka == 1){ return -1; jeżeli wcześnniej pojawiła siękropka, zwracany jest błąd else {kropka = 1; break; case 'E': if(e == 1){ ;jeżeli już pojawił się znak wykładnika zwracany jest błąd return -1; else{ E = 1; pominięcie znaku + lub w wykładniku if(napis[licznik+1] == '-' napis[licznik+1] == '+'){ licznik++; break; default: ;w przypadku innych znaków zwracany jest błąd return -1; licznik++; cout << "\nprawidlowa liczba: " << napis << endl; Ćwiczenie 1-4 Strona 3
Konwersja do postaci obliczeniowej Konwersja została zrealizowana przy pomocy koprocesora matematycznego w module asemblerowym. Procedura wykonująca to zadanie składa się z trzech części a) Przeliczanie części całkowitej Przelicz PROC NEAR PobierzBufor xor ax, ax mov si, offset Bufor FINIT FLDZ ;pobranie parametrów ze stosu ; inicjujemy FPU ; ladujemy 0 do FPU Minus: cmp byte ptr [si], '-' ; jeżeli pierwszym znakiem nie jest minus, jne Mantysa ; przejscie do przeliczania mantysy mov [Ujemna], 01h ; zaznaczenie że mantysa jest ujemna Mantysa: cmp byte ptr [si], '.' ; jeżeli napotkano kropkę je Kropka ; przejście do zliczania części ułamkowej cmp byte ptr [si], 'E' ; jeżeli napotkano znak wykładnika, je E ; przejście do liczenia wykładnika cmp byte ptr [si], '$' ; jeżeli napotkano koniec łańcucha je Dalej ; zakończenie przeliczania; FIMUL Dziesiec ; mnożymy dotychczasową wartość liczby przez 10 mov al, byte ptr [si] ; ładujemy bieżącą cyfrę w kodzie ASCII z bufora sub al, '0' ; konwersja na postać obliczeniową cyfry mov byte ptr [Cyfra], al ; załadowanie cyfry do zmiennej FIADD Cyfra ; dodanie bieżącej cyfry do wyniku ; inkrementacja offsetu jmp Mantysa ; pętla Ćwiczenie 1-4 Strona 4
b) Przeliczanie części ułamkowej Dalej: jmp Koniec Kropka: FILD Dzielnik FXCH st(1) ; załadowanie dzielnika równego dziesięć do rejestru st(0) ; zamiana zawartości rejestrów st(0) i st(1) ; teraz w st(0) jest aktualna wartość liczby a w st(1) dzielnik Kropkowanie: cmp byte ptr [si], 'E' ; przejście do liczenia wykładnika je E ; jeżeli napotkano znak wykładnika, cmp byte ptr [si], '$' ; jeżeli napotkano koniec łańcucha je Koniec ; zakończenie przeliczania mov al, byte ptr [si] ; konwersja cyfry na postać obliczeniową sub al, '0' mov byte ptr [Cyfra], al ; i załadowanie jej do zmiennej FILD Cyfra ; załadowanie cyfry do rejestru st(0) FDIV st, st(2) ; dzielenie cyfry przez aktualny dzielnik FADD ; dodanie ułamka do aktualnej cyfry FILD Dzielnik ; załadowanie liczby 10 do st(0) FMULP st(2), st ; pomnożenie dzielnika przez 10 jmp Kropkowanie ; pętla Ćwiczenie 1-4 Strona 5
c) Przeliczanie wykładnika E: FFREE st(1) ; zwolnienie miejsca na stosie zajmowanego przez dzielnik ; pominięcie znaku wykładnika LiczWykladnik Wykladnik ; wywołanie makra obliczającego wykładnik cmp Wykladnik, 8000h ; jeżeli wykładnik jest dodatni jb Plus ; skok do obsługi Petla: mov cx, Wykladnik neg cx ; obliczanie wartości bezwzględnej wykładnika E FIDIV Dziesiec ; dzielenie całej liczby E razy przez 10 loop Petla jmp Koniec Plus: mov cx, Wykladnik Petla2: FIMUL Dziesiec ; mnożenie E razy całej liczby przez 10 loop Petla2 Koniec: FFREE st(1) Zakoncz: clc ret cmp Ujemna, 1 jne Zakoncz FCHS ; zwolnienie miejsca na stosie zajmowanego przez dzielnik ; jeżeli mantysa jest ujemna ; wynik jest negowany ; ustawienie znaczników poprawności ; powrót z procedury Przelicz ENDP Ćwiczenie 1-4 Strona 6
Wyliczanie wykładnika zostało zrealizowane w następujący sposób: LiczWykladnik MACRO Wynik xor ax, ax ; tu będzie cały wykładnik xor bx, bx ; tu będzie bieżąca cyfra wykładnika xor cx, cx ; tu będzie 1 jeśli wykładnik jest ujemny cmp byte ptr [si], '-' jne DodatniWykladnik mov cx, 01h DodatniWykladnik: Dalej2: cmp byte ptr [si], '+' jne Dalej2 cmp je mov sub mov dx, 10 mul dx add ax, bx jmp DodatniWykladnik KoniecWykladnika: cmp cx, 0 je NieNeguj NEG ax NieNeguj: ENDM byte ptr [si], '$' KoniecWykladnika bl, byte ptr [si] bl, '0' mov Wykladnik, ax Ćwiczenie 1-4 Strona 7