Jednostka MMX

Transkrypt

Jednostka MMX
ARCHITEKTURA KOMPUTERÓW - LABORATORIUM
Program hybrydowy
Dokumentacja ćw. 1-4
Zuzanna Hartleb i Artur Angiel
2010-06-16
Program hybrydowy
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
mov byte ptr [di], '$'
pop di
pop si
pop cx
pop bp
ENDM
Ćwiczenie 1-4
Strona 2
Program hybrydowy
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'){
cout << "\nNieprawidlowa liczba" << endl;
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){
cout << "\nNieprawidlowa liczba" << endl;
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
cout << "\nNieprawidlowa liczba" << endl;
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
cout << "\nNieprawidlowa liczba" << endl;
return -1;
}
licznik++;
}
}
cout << "\nPrawidlowa liczba: " << napis << endl;
Ćwiczenie 1-4
Strona 3
Program hybrydowy
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
jne
mov
inc
Mantysa:
cmp
je
cmp
je
cmp
je
byte ptr [si], '-' ; jeżeli pierwszym znakiem nie jest minus,
Mantysa
; przejscie do przeliczania mantysy
[Ujemna], 01h ; zaznaczenie że mantysa jest ujemna
si
byte ptr [si], '.'
Kropka
byte ptr [si], 'E'
E
byte ptr [si], '$'
Dalej
FIMUL Dziesiec
; jeżeli napotkano kropkę
; przejście do zliczania części ułamkowej
; jeżeli napotkano znak wykładnika,
; przejście do liczenia wykładnika
; jeżeli napotkano koniec łańcucha
; zakończenie przeliczania;
; mnożymy dotychczasową wartość liczby przez 10
mov
sub
al, byte ptr [si] ; ładujemy bieżącą cyfrę w kodzie ASCII z bufora
al, '0'
; konwersja na postać obliczeniową cyfry
mov
byte ptr [Cyfra], al ; załadowanie cyfry do zmiennej
FIADD Cyfra
inc
si
; dodanie bieżącej cyfry do wyniku
; inkrementacja offsetu
jmp Mantysa
; pętla
Ćwiczenie 1-4
Strona 4
Program hybrydowy
b) Przeliczanie części ułamkowej
Dalej:
jmp Koniec
Kropka:
FILD Dzielnik
FXCH st(1)
inc si
; 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:
byte ptr [si], 'E'
E
byte ptr [si], '$'
Koniec
mov
sub
mov
al, byte ptr [si] ; konwersja cyfry na postać obliczeniową
al, '0'
byte ptr [Cyfra], al ; i załadowanie jej do zmiennej
FILD Cyfra
FDIV st, st(2)
FADD
FILD Dzielnik
FMULP st(2), st
inc si
jmp Kropkowanie
Ćwiczenie 1-4
; przejście do liczenia wykładnika
cmp
je
cmp
je
; jeżeli napotkano znak wykładnika,
; jeżeli napotkano koniec łańcucha
; zakończenie przeliczania
; załadowanie cyfry do rejestru st(0)
; dzielenie cyfry przez aktualny dzielnik
; dodanie ułamka do aktualnej cyfry
; załadowanie liczby 10 do st(0)
; pomnożenie dzielnika przez 10
; pętla
Strona 5
Program hybrydowy
c) Przeliczanie wykładnika
E:
FFREE st(1)
inc si
; 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
mov cx, Wykladnik
neg cx
; obliczanie wartości bezwzględnej wykładnika E
FIDIV Dziesiec
loop Petla
jmp Koniec
; dzielenie całej liczby E razy przez 10
Petla:
Plus:
mov cx, Wykladnik
Petla2:
FIMUL Dziesiec
loop Petla2
; mnożenie E razy całej liczby przez 10
FFREE st(1)
; zwolnienie miejsca na stosie zajmowanego przez dzielnik
cmp Ujemna, 1
jne Zakoncz
FCHS
; jeżeli mantysa jest ujemna
Koniec:
Zakoncz:
clc
ret
; wynik jest negowany
; ustawienie znaczników poprawności
; powrót z procedury
Przelicz ENDP
Ćwiczenie 1-4
Strona 6
Program hybrydowy
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
inc si
mov cx, 01h
DodatniWykladnik:
cmp byte ptr [si], '+'
jne Dalej2
inc si
Dalej2:
cmp
je
mov
sub
byte ptr [si], '$'
KoniecWykladnika
bl, byte ptr [si]
bl, '0'
mov
mul
add
inc
dx, 10
dx
ax, bx
si
jmp DodatniWykladnik
KoniecWykladnika:
cmp
cx, 0
je NieNeguj
NEG ax
NieNeguj:
mov Wykladnik, ax
ENDM
Ćwiczenie 1-4
Strona 7