Assembler [8086] mnożenie i dzielenie i inne pytania

0

Witam, chciałem poruszyć pojęcie mnożenia i dzielenia w assemblerze
dokładnie chodzi mi o to że gdy mnożymy rejestr ax przez inny rejestr to wynik jest w parze rejestrów DX:AX (czyli 2x większy pamięciowo), jak odwołać się w prawidłowy sposób aby wartości była odpowiednio interpretowana, tak aby tą wartość prawidłowo dodać do innej pary rejestrów DX:AX?
Przykłąd zadania
a =20
b =10
c =5
d =3
Wynik = "(ab+cd)/(a-d)"

Wstępnie użyłem wartości DW, prosiłbym o poprawienie jeżeli jest coś źle

wymyśliłem takie coś ale wynik jest bez przecinka i nie wiem co z tym zrobić :?


;google-wynik:     12.6470588235   
;                  ((20*10)+(5*3))/(20-3)   
;                  (200+15)/17
.MODEL  TINY
  ORG  100h
  
  
.DATA
a               DW     20
b               DW     10
c               DW     5
d               DW     3
Wynik           DD     ?
  
.CODE
				mov     ax,@DATA
				mov     ds,ax
				mov     ax, a
				mov     bx, b
				mul     bx     
				mov     cx, ax     ;cx= a*b 
				mov     ax, c
				mov     bx, d      
				mul     bx      ;ax=c*d
				add     ax, cx
				mov     cx, ax  ;cx=a*b+c*d    
				mov     ax, a
				mov     bx, d    
				sub     ax, bx
				mov     bx, ax  
				mov     ax, cx
				div     bx  
				mov     Wynik, ax
				mov     ax, Wynik
				mov     ax, 4C25h
				int     21h
			

END
 

Co w wypadku liczb zmiennoprzecinkowych które powstały z liczb całkowitych(przy dzieleniu), jak prawidłowo wyświetlić/operować na tych wartościach

0

Wynik na pewno będzie bez "przecinka" bo te wszystkie operacje są na liczbach całkowitych! div wykonuje dzielenie całkowitoliczbowe i daje też dostęp do reszty z dzielenia:
http://www.electronics.dit.ie/staff/tscarff/8086_instruction_set/8086_instruction_set.html#DIV
Więc np. 5/3 = 1 + 2 reszty

Jeśli chciałbyś mieć obliczenia zmiennoprzecinkowe to potrzeba ci do tego chyba przynajmniej .386 (albo .286?) i operacji na stosie FPU.

Niemniej dla takich małych liczb (mniejszych od 256) czemu nie robisz tego na bajtach tylko na wordach?

0

Dzięki a co w przypadku gdy mamy do pomnożenia DX:AX przez np: BX
i jak odwołać się do DX:AX gdy chce to podzielić

Niestety te wszystkie poradniki, kursy są napisane na najprostszych przykładach nie tłumacząc co się dzieje w innych bardziej złożonych operacjach (różna długość zmiennych) ;/

0

mamy do pomnożenia DX:AX przez np: BX

Nie ma takiej instrukcji po prostu. Jeśli chcesz coś takiego zrobić to musisz to zaklepać "ręcznie" i tyle. Bo rozumiesz chyba że wynik takiej operacji trzeba by teraz składać juz w 3 rejestrach? ;]

jak odwołać się do DX:AX gdy chce to podzielić

Nijak, po prostu podziel przez worda i "samo się odwoła". Jeśli zrobisz div bx to wykona się DXAX / BX, bo tak działa ten opkod i tyle.

1
Shalom napisał(a):

Jeśli chciałbyś mieć obliczenia zmiennoprzecinkowe to potrzeba ci do tego chyba przynajmniej .386 (albo .286?)

Nie; potrzeba koprocesora FPU. Był dostępny już od pierwszej generacji x86, ale był osobnym układem (właśnie koprocesorem).
Dopiero 486 miały układ FPU wbudowany w sam procesor, ale też nie wszystkie modele (486DX).

Jest bardzo wątpliwe by @krecikondexin uruchamiał swój program na procesorze niemającym FPU.

0

Dzięki za odpowiedzi ale mam jeszcze jedno pytanie
Jak zapobiegać błędnym obliczeniom, chodzi tu o różne długości argumentów (Profesor z uczelni kazał zwracać na to uwagę[mnożenie 8bitowe, 16bitow, dzielenie 16bitowe, 8 bitowe])
AX = AL * operand.
Gdy AX chcemy pomnożyć przez BL
AX jest 2x większy od BL i to może generować błędne wyniki

0

Że co? o_O Przecież jak mnożysz AX przez BL to wynik dostajesz w DX AX, właśnie dlatego że wynik mógłby się nie zmieścić w AX. Czy ty w ogóle rozumiesz co robisz?

0
Shalom napisał(a):

Przecież jak mnożysz AX przez BL to wynik dostajesz w DX AX, właśnie dlatego że wynik mógłby się nie zmieścić w AX

o takie coś mi chodziło, niestety ale te wszystkie przykłady działania są napisane na rejestrach tej samej wielkości np: AL * BL = AX, AXBX= DX:AX...
nie spotkałem się z przykładem że AX
BL=DX:AX

0

Witam, to znowu ja, tym razem chciałem prosić was o ocenę poprawnści kodu 2 programów, komentarz na początku programów opisuje co on ma robić

; Uwagi          : Program obliczajacy wzor: (a*b+c*d)/(a-d)        (program typu com)          ;
;                                                                             ;
;=============================================================================;

Prog SEGMENT
ASSUME CS: Prog, DS:Prog, ES:Prog, SS: Prog
ORG 100h
START:

Poczatek: 
mov     ax,0
mov     bx,0
mov     al, a
mov     bl, b
mul     bl
mov     cx, ax     ;cx= a*b 
mov     ax,0
mov     bx,0
mov     al, c
mov     bl, d
mul     bl      ;ax=c*d
add     ax, cx
mov     cx, ax  ;cx=a*b+c*d
mov     al, a
mov     bl, d
sub     al, bl  ;ax=a-d
mov     bx, ax
mov     ax, 1d 
mul     bx  
mov     bx, ax  
mov     ax, cx
div     bx    
mov     Wynik, al 
mov     ax,0;
mov     al, Wynik
mov     al,02h
mov ax,4c00h    
;konczymy program
int 21h

a               DB     20
b               DB     10
c               DB     5
d               DB     3
Wynik           DB     ?

prog ends
end start

; Uwagi          : Program dokonujacy odbicia lustrzanego tekstu o nieznanej  ;program typu exe
;                  dlugosci                                                   ;
;                                                                             ;
;=============================================================================;

                .MODEL  SMALL
                     
.Stack 100h
.data
    Tekst1          DB      "Jakis napis$"
    Tekst2          DB 12 dup(?)     ;zmienna pomocnicza
    count           DW 12

.code
Start:
                mov     ax, @data
                mov     ds, ax
                mov     cx, count    ;cx=11
                mov     si, 0
                mov     di, 0   
                add     di,count     
                dec     di  
                mov     al, tekst1[di]   
                mov     tekst2[di],al  
                dec     di
                
petla:          mov     al, tekst1[si]   
                mov     tekst2[di],al
                inc     si
                dec     di                   
loop petla                
wypisz:    
        mov ah,09h 
mov dx,offset tekst2    ;wyswietlamy napis 
int 21h 

mov ax,4c00h    ;konczymy program 
int 21h 

end start
0
                mov     di, 0   
                add     di,count     
                dec     di  

Serio?
2. Po co dwa razy skopiowałeś

                mov     al, tekst1[di]   
                mov     tekst2[di],al  
                dec     di

i jeszcze raz błędnie bo bez inkrementacji si?
3. nieznanej długości a potem DB 12 dup(?) to jak to jest? :D

0

1- zagiąłeś mnie tym "dec di", umknęło mi :P chciałem pożerować rejestry
2- chodziło o to że ostatni znak "$" zawsze przepisać na ostatnim miejscu aby można było wyświetlić wynik na ekranie
3- do opracowania mam obliczanie długości, ale na chciałem sprawdzić czy na "obliczonej" długości zadziała, używałem "emul8086" i w wartości rejestrów dobrze przepisywało znaki, dosbox i TD to masakra dla mnie w obsłudze, nie wiem jak ustawić aby rejestry pokazywały wartość dziesiętną lub znaki :/

0
  1. No ale teraz to zrobiłeś to w mega nieczytelny sposób jak dla mnie bo nie wiadomo co i dlaczego tam się dzieje.
0
 
                .MODEL  SMALL
 
.Stack 100h
.data
    Tekst1          DB      "Jakis napis$"
    Tekst2          DB 12 dup(?)     ;zmienna pomocnicza
    count           DW 12
 
.code
Start:
                mov     ax, @data
                mov     ds, ax
                mov     cx, count    ;cx=11
                mov     si, 0
                mov     di, 0   
                add     di,count     
                dec     di  
                mov     al, tekst1[di]   
                mov     tekst2[di],al  
                dec     di
 
petla:          mov     al, tekst1[si]   
                mov     tekst2[di],al  
                cmp    si, count
                inc     si
                dec     di                   
loop petla                
wypisz:    
        mov ah,09h 
mov dx,offset tekst2    ;wyswietlamy napis 
int 21h 
 
mov ax,4c00h    ;konczymy program 
int 21h 
 
end start

nie wiem czy dobrze to ugryzłem, nie wiem jak zrobić obliczanie długości ;/ cmp jakoś za bardzo nie chce mnie słuchać ;/
już nie powinno wyskakiwać poza zakres "tablicy"
te nieczytelne di, si są potrzebne do dobrego przepisania "$" ;/

0

A musisz go "przepisać"? ;) Nie możesz skopiować danych aż do n-1 a na koniec ręcznie wpisać $? :)

0

zadanie jest takie jakie podałem, sposób dowolny byle osiągnąć cel zadania :) pobawię się żeby nie przepisywać :)

0

Podjąłem próbę zrobienia t na jednej tablicy ale nie dałem rady ale za to znacznie przerobiłem ten program :)
poprosiłbym o ocenę programu czy jest poprawnie napisany :)

.MODEL  SMALL
 
.Stack 100h
.data
    Tekst1          DB      "Jakis napis$"
    Tekst2          DB     dup(tekst1)    
.code
Start:
                mov     ax, @data
                mov     ds, ax  
                mov     di, 0
zlicz:   
                mov     al,tekst1[di]   
                cmp     tekst1[di],'$' 
                je      prepare
                inc     di 
loop zlicz                 
prepare:                

                mov     al, tekst1[di]   
                mov     tekst2[di],al  
                dec     di
 
petla:          mov     al, tekst1[si]   
                mov     tekst2[di],al  
                cmp     di, 0 
                je      wypisz
                inc     si
                dec     di                   
loop petla                
wypisz:    
        mov ah,09h 
mov dx,offset tekst2    ;wyswietlamy napis 
int 21h 
 
mov ax,4c00h    ;konczymy program 
int 21h 
 
end start
0
  1. brakuje zerowania si
               mov     al,tekst1[di]   
               cmp     tekst1[di],'$'

Po co wpisujesz do rejestru al skoro go nie używasz?

0

Zerowanie dodałem po opublikowaniu na 4um a co do " mov al,tekst1[di] " to faktycznie nie wymagane, już usunięte :)
Dzięki za szybką odpowiedź :)

0

jednak jest coś nie tak

 Tekst2          DB     dup(tekst1)   

nie wiem jak skopiować wielkość "zmiennej/tablicy" aby dostać pustą kopię tego samego "przedziału" (np tekst1 ma 20 pól to na podstawie tekst1 chce zrobić tekst2 o 20 polach gdzie 20 pochodzi od tekst1), Emu8086 przegryzł to ale dla od miany dosbox+Tasm nie ;/ jakieś propozycje?
@Edit

Tekst1          DB      "Jakis nasz napis$"  ;nasz napis
 sizee            equ  $-Tekst1
 Tekst2          DB      sizee dup(?)     ;zmienna o wielkosci tekstu1

takie coś zrobiłem i zadziałało ;)

1 użytkowników online, w tym zalogowanych: 0, gości: 1