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

Assembly Programlama-2

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 00000111 kere ______00100100__/00000111 00000111 __00100100______/00000111 imdi 00000111 -------------__000010 _00001000_______/00000111 00000111 00001000________/00000111 sonuna 00000111 -------------00000001 böleni bir basamak sola kaydırıp bölünenin en soluyla kar ıla tırıyoruz bakıyoruz 00000000'da 00000111 kaç kere var? (ne biçim bi soru bu imdi. Ya 1 vardır ya da yoktur tabii ki :) ) Yok. O zaman bölüneni bir daha sola kaydırıp bakalım. Yine yok. Böyle devam edelim. Altıncı i lemde görüyoruz ki 00001001 sayısında 00000111 bir kere var ( ehehe ). bunu bölünenden çıkarmamız gerekiyor. Bölünen sayı 00001000 haline geldi. Artık böyle devam edecez. 00001000'da 00000111 yok. 00001000'da 00000111 bir kere var. Yine çıkarmamızı yapıyoruz. Artık sayımızın geldi imiz için daha fazla kaydırma-kontrol etme yapmıyoruz. Sonuçta elimizde 00000001 eldesi kaldı. Nihai sonuç da: 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 comf sayi ;(sayi-1)->sayı ;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...

Sign up to vote on this title
UsefulNot useful