You are on page 1of 4

Assembly Programlama-2

Bu bölümde 16 bit bölme yapmayı görecez.

Bölmenin nasıl yapıldı ını inceleyelim. Sonra i lemcimize nasıl yaptıraca ımıza karar verelim.
8 bit için örnek:
00100100/00000111=00000101 kalan 1

_______00100100_/00000111 böleni bir basamak sola kaydırıp bölünenin en soluyla kar ıla tırıyoruz
00000111 bakıyoruz 00000000'da 00000111 kaç kere var? (ne biçim bi soru bu imdi. Ya 1
kere
vardır ya da yoktur tabii ki :) ) Yok. O zaman bölüneni bir daha sola kaydırıp bakalım.
______00100100__/00000111 Yine yok. Böyle devam edelim.
00000111

__00100100______/00000111 Altıncı i lemde görüyoruz ki 00001001 sayısında 00000111 bir kere var ( ehehe ).
imdi
00000111 bunu bölünenden çıkarmamız gerekiyor. Bölünen sayı 00001000 haline geldi.
-------------- Artık böyle devam edecez.
__000010

_00001000_______/00000111 00001000'da 00000111 yok.


00000111

00001000________/00000111 00001000'da 00000111 bir kere var. Yine çıkarmamızı yapıyoruz. Artık sayımızın
sonuna
00000111 geldi imiz için daha fazla kaydırma-kontrol etme yapmıyoruz.
-------------- Sonuçta elimizde 00000001 eldesi kaldı. Nihai sonuç da:
00000001 yok:yok:yok:yok:yok:var:yok:var-->00000101

Umarım her ey açıktır. Yukarıya baktı ımızda kar ıla tırma gibi çipin tanımadı ı bir i lem yapıyoruz. Kar ıla tırmanın amacı
bir sayının bir di erinden küçük mü büyük mü oldu unu anlamak oldu undan bu iki sayı ile çıkarma i lemi yaparsak ve
sonuca bakarsak hangisinin daha büyük oldu unu anlayabiliriz.
Ancak elimizdeki i lemci yalnız 8 bit pozitif tamsayılarla i lem yaptı ı için bir sorunumuz var.

Negatif sayıları göstermenin bilgisayar dünyasında çe itli yolları vardır. Burada bize gerekli olanı inceleyecez. Öncelikle
sayıları sınırlı bit miktaralarıyla gösterdi imizi hatırlayalım. Yani bir i lemin sonucu 8 bit bir makinede 8. biti geçerse o i lemin
sonucu genelde oldu u haliyle kullanılmaz. Carry ve zero flagleri yardımıyla ne yapaca ımıza karar veririz.

Bu kadar ara yeter imdi negatif sayıları nasıl gösterdi imize gelelim. Sayıdan önce 1 çıkarıyoruz. Sonra bütün bitlerin tersini
alıyoruz.
Örnek: -00110110 = 11001010

00110110-1=00110101
00110101->11001010
Neden böyle oldu unun eminim doyurucu bir matematiksel açıklaması vardır ama burada veremeyecem.

Bir A sayısı alalım. A sayısının negatifini öyle gösterebiliriz de il mi?: A+(-A)=0


Yukarıdaki örne imize bakarsak:

_00110101
_11001010
+--------------
100000000

Dokuzuncu bit olmasaydı amacımıza ula mı olacaktık ama biz zaten sayıları 8 bitle gösterdi imiz için sorun yok!
Ayrıca -(-A)=A

11001010-1=11001001
11001001->00110110

Artık 8 bit ile -128,+127 arasındaki sayıları gösterebiliriz. Bu sayılarla do rudan çıkarma yerine negatifini aldıktan sonra
toplama yapabiliriz. 16f628 ve benzeri di er çiplerdeki SUBWF ve SUBLW komutlarının yaptı ı i i buna benzetirsek önemli
sonuçlara varırız:
• Negatif aldıktan sonra toplama i leminde elde etti imiz carry 1 ise çıkarmanın sonucu pozitiftir.
• Negatif aldıktan sonra toplama i leminde elde etti imiz carry 0 ise çıkarmanın sonucu negatiftir.
Ama i bu kadar basit de il çünkü 00000000'ın tersi yine 00000000. Sonucun negatif olmasının, ilk sayının ikinciden küçük
olmasını "garantilemesini" istiyoruz. Bu sebeple PIC i lemcimizde ( burada 16f628a, en azından MPLAB SIM'de ) SUBxx
komutuyla 0'dan 0 çıkarınca carry 1 de erini alır.
Çıkarma i lemine de bakalım. 16 bit çıkarma yaparken low byteların sonucu negatifse borç alma var demektir ( carry=0 ).
Daha önce toplamada yaptı ımız gibi 256 tabanında dü ünürsek sonucun high byteından 1 çıkarırız.
Yine toplama yaparken önce sonucun low byteını bulmu tuk. Eldeye göre sonucun high byteını 1 arttırıp öyle devam etmi tik.
Farketti iniz gibi ilk de i kenin içindeki de er de kaybolmu tu. Aslında önce high byteı hesaplayıp sonra low byteların
sonucuna göre düzeltmek daha temiz bir yol oldu u için toplama ve çıkarmada artık tercih etti imiz yöntem olacak. Böylece
de i kenlerden hiçbirini kaybetmeden sonucu ba ka bir de i kene aktarabiliriz. Bölme algoritmasını yazarken nasıl oldu unu
göreceksiniz.

Bölme i lemine geldik sonunda. 8 bit bölme yapmak çok sıkıcı olaca ından direk 16 bite geçtim :-). 16 bit sayıyı bir ba ka 16
bit sayıya bölecez.
Yazının ba ında bölünenin kendisi kadar daha kayacak yere ihtiyacı oldu unu gördük. Sonra kar ıla tırma için de geçici bir
de i ken lazım. Kar ıla tırmayı çıkarma i lemiyle yapıp sonucu da buraya yerle tiriyoruz. Yalnızca carry biti sonucun negatif
ya da pozitif oldu unu göstermeye yeter ama e er sonuç pozitifse aynı çıkarmayı tekrar yapmamak için geçici de i kenin
içeri ini kullanabiliriz.

Kodu yazalım:

list p=16f628a
#include p16f628A.inc
cblock 0x70
al ;bolunen low byte
ah ;bolunen high byte
eal ;bolunen icin kayacak low byte=0
eah ;bolunen icin kayacak high byte=0
bl ;bolen low byte
bh ;bolen high byte
dl ;gecici degisken low byte
dh ;gecici degisken high byte
rl ;sonuc low byte
rh ;sonuc high byte
co ;sayac=16
endc
org 0x0000
goto basla
org 0x0005
bol:
clrf eah ;bolunen icin kayacak yeri temizliyoruz
clrf eal
clrf rh ;sonucu temizle
clrf rl
movlw 0x10
movwf co ;sayac=16
lb1:
rlf al,f ;boluneni kaydiriyoruz ki en soldaki parcasini kontrol edebilelim
rlf ah,f
rlf eal,f
rlf eah,f
movf bh,w ;buraya dikkat. once bolunenin high byteindan bolenin high byteini cikarip
subwf eah,w ;sonucu gecici degiskene yaziyoruz
movwf dh
movf bl,w ;simdi low bytelarla ayni islem
subwf eal,w
movwf dl
btfss STATUS,C;low bytelarin sonucu negatifse gecici degiskenin high byteini 1 azaltiyoruz
decf dh,f
rlf rl,f ;karsilastirmanin en son sonucu carryde. bu komutla dogrudan sonuca yazabiliriz
rlf rh,f
btfss rl,0 ;karsilastirmanin en son sonucu artik carryde degil burada ( sonucun en sag biti )
goto lb2
movf dl,w ;eger pozitifse bolunenin degerini gecici degiskendeki degerle degistir
movwf eal
movf dh,w
movwf eah
lb2: ;eger negatifse bisey yapma
decfsz co,f ;isimiz bitti mi?
goto lb1 ;bitmediyse basa don
return
basla:
movlw 0x24 ;ah:al=36
movwf al
clrf ah
movlw 0x5 ;bh:bl=5
movwf bl
clrf bh
call bol ;36/5 sonuc rh:rl ikilisinde kalan eah:eal iklisinde
goto $ ;dur
end

Kar ıla tırmanın sonucunu do rudan rlf rl,f ve rlf rh,f komutlarıyla saklamamızın nedeni zaten sonucu soldan sa a
doldurmamız. ( Aynen günlük hayatta yaptı ımız bölme gibi ). anslıyız ki kar ıla tırma sonucu pozitif oldu unda carry 1
de erini alıyor. 0 olsaydı bölmenin sonunda sonucun bitlerini ters çevirmemiz gerekecekti.

Her ne kadar negatif sayılarla i lem yapıyor gibi görünse de aslında algoritmamız sadece pozitif sayıları birbirine bölebilir.
Ayrıca bir sayıyı sıfıra böldü ünüzde 0xFFFF sonucunu verir. Bu yüzden yukarıdaki kodu oldu u gibi kullanırsanız bunlara
dikkat etmelisiniz.

Madem yazdı ımız çarpma-bölme algoritmları sadece pozitif sayı kabul ediyor biz de negatif sayıları tespit edip pozitife
çevirelim. Kaç bit olursa olsun bir sayıyı negatif kabul ediyorsak en soldaki bitinin daima 1 olması gerekir. 0 ise sayı pozitiftir.

8 bit bir sayıyı -1 ile çarpmak için:

decf sayi,f ;(sayi-1)->sayı


comf sayi ;bitleri ters cevir

16 bit bir sayıyı -1 ile çarpmak için:

decf sayilow,f ;sayinin low byteindan 1 cikariyoruz


btfss STATUS,C;borc alma varsa high bytedan da 1 cikaracaz
decf sayihigh,f
comf sayihigh
comf sayilow ;bitleri ters cevir

Biraz daha fazla kod yazarak artık negatif sayılarla da i lem yapabiliriz. Sonuçları uygun i arete dönü türecek kodları da
unutmayın :-).

Bu seferlik benden bu kadar. Yoruldum, sonra görü ürüz...

Hazırlayan: Görkem Demirta


ikayetler e1448596@ceng.metu.edu.tr adresine...

You might also like