Cześć.
Napisałem program w assemblerze, który oblicza kwadrat liczby zapisanej w systemie IEEE-754. Wartości podajemy w systemie HEX i wynik także dostajemy w HEX.
Problem jest gdy podaje liczby z zakresu od -0.9 do 0.9. Wtedy program się sypie. Dla innych liczb wykonuje się poprawnie. Sam już nie widzę dlaczego tak się dzieje. Dlatego zamieszczam kod tutaj, może ktoś pomoże znaleźć błąd.
sts segment 'stack' stack
db 512 dup(0)
sts ends
dane segment
txt1 db "Pierwsza liczba IEEE-754: $"
txt4 db "________(HEX)$"
txt3 db "Wynik: $"
znak db 0
wynik DB 4 dup(?)
cecha DB ?
txt2 db "Program wykonuje potegowanie liczby w systemie IEEE-754. $"
cecha_potega DW ? ;przechowuje ceche po spotegowaniu
mantysa DB 3 dup (?)
mantysa_potega DB 6 dup (?) ;przechowuje wynik mantysy po spotegowaniu
komunikat db "przepelnienie$"
dane ends
include macros.asm
prog segment
assume cs:prog,ds:dane,ss:sts
P486N
start:
mov ax,seg dane
mov ds,ax
clrscr
ustaw_kursor 0,0
wyswietl txt2
ustaw_kursor 2,0
wyswietl txt1
ustaw_kursor 2,25
wyswietl txt4
ustaw_kursor 3,0
wyswietl txt3
ustaw_kursor 3,6
wyswietl txt4
ustaw_kursor 2,25
;wczytywanie liczby
call wczytywanieLiczby
mov cl,8
shl edx,cl
shl edx,cl
mov ebp,edx ;tymczasowa kopia liczby
call wczytywanieLiczby
;rozbijanie liczby na ceche, mantyse i znak
mov eax,ebp ;eax = liczba(ebp)
rol eax,1
;liczenie cechy liczby IEEE-754
rol eax,8
sub al,127
mov cecha,al
push eax ;zapamietujemy na pozniej
MOV AH,0
;MOV AL,cecha
;SUB AX,127 ;system spolaryzowany
;mnozenie przez 2 spowoduje przesuniecie w lewo
SHL AX,1
SUB AX,23 ;jako, ze przy mnozeniu nie uwzgledniono przecinka, ktory trzeba przesunac o 22 poz. b. w lewo
MOV cecha_potega,AX
;zapisanie mantysy do zmiennej
pop eax
rol eax,23
and eax,7FFFFFh ;zeby na 24 bicie od prawej bylo 0 | 0-zeruje 1-przepisuje bit
mov mantysa[2],ah
mov mantysa[3],al
shr eax,8
or ah,80h
mov mantysa[0],ah
;zerowanie na wszelki wypadek
mov eax,0
;zerowanie mantysa_potega
MOV CX,6
MOV SI,0
zeruj:
MOV mantysa_potega[SI],0
INC SI
LOOP zeruj
;mnozenie w petli
MOV SI,2
MOV DI,2
wykonanie_mnozenia:
MOV AH,mantysa[DI]
MOV AL,mantysa[SI]
MUL AH
MOV BX,SI
ADD BX,DI
ADD mantysa_potega[BX+1],AL
ADC mantysa_potega[BX],AH
CMP SI,0
JE dekrementacja_DI
DEC SI
JMP wykonanie_mnozenia
dekrementacja_DI:
CMP DI,0
JE normalizowanie
DEC DI
MOV SI,2
JMP wykonanie_mnozenia
normalizowanie:
;normalizowanie - przesuwanie mantysy i zmiana cechy
;aby poprawna, musi byc 0,0,1,x,x,x
;jako, ze byla dodana 1, to zawsze przesuwanie w prawo
;na pierwszych 3 pozycjach - nadmiarowa
CMP mantysa_potega[0],0
JNE przesuniecie_normalizowanie
CMP mantysa_potega[1],0
JNE przesuniecie_normalizowanie
CMP mantysa_potega[2],0
JNE przesuniecie_normalizowanie
;w tym momencie oznacza, ze na 1 pozycji z [3] jest 1
JMP sprawdzenie_wyniku
przesuniecie_normalizowanie:
MOV CX,6 ;przesuwa 6 bajtow
MOV SI,0
CLC ;musi dostawic 0 na poczatek
przesuniecie_normalizowanie_petla:
RCR mantysa_potega[SI],1
INC SI
LOOP przesuniecie_normalizowanie_petla
INC cecha_potega
JMP normalizowanie
sprawdzenie_wyniku:
;powrot do normalnego zapisu cechy
ADD cecha_potega,127
;sprawdza na obecnosc nieskonczonosci
CMP cecha_potega,00000h ;wskazuje, ze cecha ujemna i z zakresu -127..128; mniejsza to za mala
JL tworz_zero
CMP cecha_potega,000FFh ;wskazuje, ze cecha jest dodatnia i z zakresu -127..128; przekroczenie w gore to nieskonczonosc
JA tworz_nieskonczonosc
;tworzy liczbe
MOV AL,mantysa_potega[3]
AND AL,01111111b ;wyeliminuje 1,xxx, czyli zbedna jedynke
MOV wynik[1],AL
MOV AL,mantysa_potega[4]
MOV wynik[2],AL
MOV AL,mantysa_potega[5]
MOV wynik[3],AL
MOV AX,cecha_potega
MOV wynik[0],AL ;mlodsza czesc
MOV AH,0 ;zmienna pomocniczna
SHR wynik[0],1 ;pozostawia znak
ADC AH,0 ;dodaje 1 jesli uciekla z wynik[0]
SHL AH,1
SHL AH,1
SHL AH,1
SHL AH,1
SHL AH,1
SHL AH,1
SHL AH,1 ;przesuwa na wlasciwa pozycje
ADD wynik[1],AH
JMP wyswietlenie_liczby
tworz_nieskonczonosc:
MOV wynik[0],01111111b
MOV wynik[1],0FFh
MOV wynik[2],0FFh
MOV wynik[3],0FFh
RET
tworz_zero:
MOV wynik[0],0
MOV wynik[1],0
MOV wynik[2],0
MOV wynik[3],0
RET
wyswietlenie_liczby:
ustaw_kursor 3,6
mov ebx,0 ;przypisanie wyniku do rejestru ebx
mov bh,wynik[0]
mov bl,wynik[1]
mov cl,8
shl ebx,cl
shl ebx,cl
mov bh,wynik[2]
mov bl,wynik[3]
;zamiana na ASCII
mov ch,0 ;zlicza wypisane znaki
ety1:
cmp ch,8
je koniec
mov dl,0
mov cl,0
ascii:
cmp cl,4
je wypisz_znak
shl ebx,1
jnc ety3
add dl,1
ety3:
shl dl,1
inc cl
jmp ascii
wypisz_znak:
shr dl,1
add dl,48
cmp dl,57
jbe ety2
add dl,7
ety2:
mov al,dl
mov ah,0Eh
int 10h
inc ch
jmp ety1
jmp koniec
przepelnienie:
ustaw_kursor 4,0
mov ax,seg komunikat
mov dx,offset komunikat
mov ah,9
int 21h
koniec:
mov ah,7
int 21h
mov ah,4ch
int 21h
wczytywanieLiczby:
mov eax,0
mov cx,4
mov edx,0 ;wynik
mov ebx,10h ;mnoznik
wczytaj:
mov ah,0
int 16h
cmp al,'0'
jb wczytaj
cmp al,'9'
jbe wczytaj_dalej1
cmp al,'A'
jb wczytaj
cmp al,'F'
jbe wczytaj_dalej1
cmp al,'a'
jb wczytaj
cmp al,'f'
ja wczytaj
wczytaj_dalej1:
mov ah,0Eh
int 10h
mov edi,eax ;5*16=80
mov eax,edx
mul ebx ; ax*bx
mov edx,eax
mov eax,edi
sub al,48
cmp al,9
jbe wczytaj_dalej2
sub al,7
cmp al,15
jbe wczytaj_dalej2
sub al,32
wczytaj_dalej2:
mov ah,0
add edx,eax
jc przepelnienie
loop wczytaj
wczytywanieLiczby_dalej1:
mov cx,0
ret
prog ends
end start