2 Nisan 2017 Pazar

BİLGİSAYAR ORGANİZASYONU

Merhaba arkadaşlar bu yazımda derste gördüğüm kadarıyla SAL, MAL, TAL komutlarından bahsedeceğim. Final sınavıma az kaldı hem ben burada anlatmaya çalışarak hazırlanmış olacağım hemde ihtiyacı olanlara ufakta olsa bir yardımım dokunsun isteğindeyim. Derslere başlamadan önce yazdığım kodları SPIMSAL isimli programda derleyeceğimi belirtmek isterim... Son olarak işin teknik tanımsal kısımlarından bahsetmeyi düşünmüyorum direk komutların nasıl yazıldığı ne anlam ifade ettiği kısımlarına gireceğim, teorik kısımlar zaten bolca internette kaynak olarak bulunmaktadır. MIPS platformunda örnekler yapacağım. MIPS 32 bit işlemciye sahip, komut sayısı az, belleğe sadece load store ile erişim oluyor.

SAL(SIMPLE ABSTRACT LANGUAGE)

TAL ve MAL'dan daha yüksek seviyelidir. Assembly dili ile yüksek seviyeli diller arasındaki boşluğu doldurur. Basit bir örnekle başlayalım

ÖRNEK: 5 sayının ortalamasını alan programı SAL yazalım.

______________________________________________________________
.data
ort: .word
sayi1: .word 20
sayi2: .word 13
sayi3: .word 82
sayi4: .word 32
sayi5: .word 18

.text
__start: add ort, sayi1, sayi2
add ort, ort, sayi3
add ort, ort, sayi4
add ort, ort, sayi5
div ort, ort, 5
put  ort
done
_______________________________________________________________
Öncelikle .data kısmında 5 tane sayımızı ve ortalama değeri tutacağımız ort değişkenini tanımlıyoruz ve ilk değer ataması yapıyoruz. Tanımlama ve atama stili yukarıda gösterildiği gibidir. Tanımlamalar bitince .text kısmında kod parçacığını yazıyoruz add komutu sayi1 ile sayi2 yi toplayıp ort değişkenine atar. Aynı anda tüm sayıları toplayamadığımızdan ikili şekilde sırayla ort değerine ekliyoruz. Ekleme işlemi bitince div komutu ile ort'daki toplam değeri 5'e bölüp tam kısmını yenide ort'a atar. Put ilede ekrana bastırıyoruz. done komutu programın sonlanması için işletim sistemine çağrıda bulunur.

Şimdide yüksek seviyeli bir dildeki bir komutu SAL'a çevirelim bu şekilde mantık daha iyi oturucaktır diye düşünüyorum. Oldukça basit bir C kodu ile başlayalım.



ÖRNEK:  for( i=1; i<=100;i++ ){ printf("%d",i); } şeklindeki C kodunu SAL'a çevirelim
______________________________________________________________
.data
i: .word 0

.text

__start:
kontrol: bgt i, 20, bitir  
put i
put '\n'
add i, i, 1
b kontrol
bitir:
done
______________________________________________________________
Aynı şekilde tanımlamalarımızı yaptık tek bir değişken yeterlidir. Kontrol etiketinde bgt komutu ile 
i'yi kontrol ediyoruz. Komut i 20'den büyük olduğunda bitir etiketine gönderir ve program sonlandırılır. Etiket sağlanmıyorsa bi alt satıra iner ve i'yi put ile ekrana basar put '\n' ile alt satıra iner. Ekrana basma işlemi tamamlandığına göre i sayacımızı bi alt satırda arttırırız sonra b koşulsuz dallanma komutuyla kontrol etiketine yeniden gidip yeni değer için kontrol yapmalıyız. Bu şekilde işle i>20 olana kadar devam eder.


ÖRNEK:  1'den n(sayi2)'e kadar olan sayıları ekrana basan program
______________________________________________________________
.data
sayi1: .word 
sayi2: .word 5
carpim: .word 0
sonuc: .word 

.text


__start:

move sonuc, 0
move sayi1, 1

dongu: bgt sayi1, sayi2, bitir

          mul   carpim, sayi1, sayi1
          add   sonuc, sonuc, carpim
          add   sayi1,sayi1,1
          b       dongu
bitir: put sonuc
done
______________________________________________________________

ÖRNEK:  1'den 10'a kadar olan sayıların çarpımını ekrana basan program
______________________________________________________________
.data

girdi:         .asciiz "Birden 10'a kadar olan sayilarin carpimi: "
i:         .word 1
carpim: .word 1
newline: .byte '\n'

.text
__start:     puts girdi
        puts newline
dongu: bgt i, 10, bitir                     #ilk deger ikinciden buyukse etilete gider

        mul carpim, carpim, i
        add i, i, 1
        b dongu
bitir: put carpim
done
______________________________________________________________

Bu iki örnekde diğer örneklere çok benzediğinden açıklama gereği duymadım. Eğer takıldığınız noktalar olursa yorum olarak sorabilirsiniz

Basit örneklerden sonra biraz daha karışık örneklere geçelim. Şimdiki örneğimiz yeni başlayanlar için biraz karışık gelebilir gözümüz korkmasın mantığını kavramaya başlayınca karışık örnekleride rahatça yapabiliriz. Önemli olan yapmak istediğimiz işlemi tam olarak anlayabilmek ne yapacağımızı kafamızda sıralayabilirsek koda çevirmek oldukça basittir

ÖRNEK:32 bitlik bir sayıyı ekrana 10 tabanında bastıran kodu yazalım
______________________________________________________________
.data
sayi: .word 0x00000034
mask: .word 0x00000001
sonuc: .word 0
sayac: .word 0
tut: .word 0
binary: .word 1
deger: .word  0

.text
__start:

dongu:
beq   sayac, 33 ,bitir
and tut, sayi, mask
mul  deger, tut, binary
mul binary, binary, 2
add sonuc, sonuc, deger
srl sayi,sayi,1
add  sayac, sayac, 1
dongu
bitir:
put  sonuc
done
______________________________________________________________
Evet arkadaşlar bu örneğide oldukça detaylı açıklamaya çalışacağım daha sonraki örneklerde bu kadar detaylı ilerlemeyeceğim. Tanımlama alanımızda hexadecimal bir sayı var kodumuz onu decimal düzene çeviriyor. Öncelikle bu çevirmenin mantığını açıklayayım elimizde 32 bitlik binary bir sayı var birinci bitini maskemle and'leyeceğim basamak değerini bulacağım daha sonra ikinci bitimi maskemle andleyeceğim onunda basamak değerini bulacağım öncekine ekleyeceğim bu şekilde 32 bitin tamamını gezip işlemimi tamamlayacağım gözümüzde canlanması açısından yukarıdaki hexadecimal sayıyı decimal yazalım.

0000 0000 0000 0000 0000 0000 0011 0100 = 0x00000034  =4+3*16= 52 yani sayımız decimal olarak 52 ye karşılık gelecek...

Şimdi kodumuzu incelemeye başlayalım... 
  • Döngü etiketine girer girmez sayacımı kontrol etmeyi tercih ettim siz dilerseniz bunu etiketin sonunda da yapabilirsiniz tabi işlemler buna göre ufak tefek değişiklik gösterebilirler.
  • 2. satırda sayi ile mask'i andleyip tut değişkenine atadım yani sayi'daki basamak da 1 var ise 1'i 0 var ise 0'ı tut'a atamış oldum.
  • 3.satırda tut ile binary çarpıp değere atadım.Burda değer basamak değerini ifade eder ikilik düzende olduğumuzdan ilk basamak için binary 1 ikinci basamak için 2 üçüncü basamak için 4 şeklinde artacaktır yani tut ile binary çarpıp değer değişkenime atadığımda o basamakdaki sayının değeri tutulur.
  • 4.satırda binary'i 2 ile çarptık çünkü basamak değeri bi sonraki satırda iki ile orantılı olarak artmalıdır.
  • 5.satırda bulduğumuz basamak değerini sonuca ekliyoruz bu şekilde 32 bit için her basamağı ekleyerek ilerleyeceğiz.
  • srl komutu ile sayımı 1 birim sağa öteliyoruz yani bi sonraki basamak ile and'leme işlemini yapabilmek kaydırıyoruz.
  • Döngü sayacımızı 1 arttırıyoruz çünkü 32 bite ulaşıp ulaşmadığımız kontrol etmeliyiz.
  • Son olarak koşulsuz dallanma ile döngü başına dönüyoruz.
  • Döngü başındaki dallanma komutu koşulu sayac=33 olduğunda bitir etiketine gönderecektir. Bu etikette sonuc değerini put ile ekrana basar.Sonuc da sayımızın decimal karşılığı bulunmaktadır.
  • Daha sonra done komutu ile program sonlanır.


ÖRNEK: Decimal bir sayının kaç tane 1 bitine sahip olduğunu bulan program
______________________________________________________________
                   .data
sayi:    .word 19
str:            .asciiz  "Girdiginiz sayida bulunan 1 sayisi: "
adet:    .word 0
sayac:    .word 0
kalan:       .word
bolum:     .word

                   .text

__start:

dongu: bgt sayac, 32, bitir
        beq sayi, 0, bitir
        rem kalan, sayi, 2
        div sayi, sayi, 2
        add sayac, sayac, 1
        beq kalan, 1, birVar
        b dongu

birVar: add adet, adet, 1
        b dongu

bitir: puts str
        put adet
done
______________________________________________________________
Bu örnek için öncelikle bizden ne istendiğine bakalım. Problemi  anlayınca gerisi daha kolay.Şimdi elimizde 19 decimal sayısı var ve biz binary olarak ne kadar 1 barındırdığını merak ediyoruz. Öncelikle test için 19 u binary yazalım:
0000 0000 0000 0000 0000 0000 0001 0011 => 3 tane 1 bulmalıyız

  • bgt  sayac, 32, bitir  komutuyla 32 bitin tamamı kontrol edildiyse döngüden çıkılır.
  • Bir diğer döngü bitirme koşuluda sayi=0 olmasıdır çünkü sayı sıfıra ulaştıysa 32 bitin tamamını kontrole gerek yoktur. bunuda beq sayi,0,bitir komutuyla kontrol ederiz
  • 19u sürekli 2'ye böldüğümüzde kalan 1'ler bizim binary sayımızda kaç tane 1 olduğunu gösterir bu yüzden kalanları tutup 1 olduğunda adet değişkenini arttırmalıyız.                                    
  • rem kalan, sayi, 2   komutuyla kalanı tutarız          
  • div sayi, sayi, 2   komutuylada sayiyi her turda 2'ye bölerek küçültürüz
  • Her turda sayacı arttırmayı unutmamalıyız ve yine her turda kalan 1 mi diye kontrol ettirip 1 ise adeti arttırmalıyız




ÖRNEK: İki sayısının kaç tane aynı biti olduğunu bulduran program
______________________________________________________________
.data
sayi1: .word 35
sayi2: .word 0
temp1: .word
temp2: .word
i:         .word 0
adet: .word 0



.text
__start:
dongu: beq i, 32, bitir
        rem temp1, sayi1, 2
        rem temp2, sayi2, 2
        div sayi1, sayi1, 2
        div sayi2, sayi2, 2
        add i, i, 1
        beq temp1, temp2, ayni
        b dongu

ayni:      add adet, adet, 1
        b dongu

bitir:
        put adet
done
______________________________________________________________
Bu örnekde bir önceki örnekle çok benzerdir. Gene aynı mantıkla her ikisayının sırasıyla bitindeki değer temp değişkenine atanır ve karşılaştırılır eğer aynı ise adet değişkeni arttırılır. Bu işlem 32 bit tamamlanana kadar yapılır.


Şimdilik bu kadar SAL örneğinin yeterli olduğunu düşünüyorum MAL ve TAL'ada değindikten sonra gene duruma göre karışık örneklere yer verebilirim.

MAL(MORE ABSTRACT LANGUAGE):
Mips Risc mimarisinde çoğu mal komutunun birebir gerçek assembly dili karşılığı olsada MAL bazı soyut komutlar barındırır.

MAL anlatımınıda SAL'da yazdığım komutların MAL karşılıklarını yazarak ve açıklamaya çalışarak ilerleyeceğim umarım yararı olur. SAL'da yazdığımız ilk örnek 5 sayının ortalamasını bulan programdı şimdi bunu MAL'da inceleyelim 

ÖRNEK: 5 sayının ortalamasını alan programı MAL'da yazalım. 
______________________________________________________________
lui  $1,  4097
lw  $4,  4($1)
lui  $1,  4097
lw  $2,  8($1)
add  $2,  $4, $2
lui  $1,  4097
sw  $2,  0($1)               #add ort, sayi1, sayi2

lui  $1,  4097
lw  $4,  0($1)
lui  $1,  4097
lw  $2,  12($1)
add  $2,  $4, $2
lui  $1,  4097
sw  $2,  0($1)               #add ort, ort, sayi3

lui  $1,  4097
lw  $4,  0($1)
lui  $1,  4097
lw  $2,  16($1)
add  $2,  $4, $2
lui  $1,  4097
sw  $2,  0($1)               #add ort, ort, sayi4

lui  $1,  4097
lw  $4,  0($1)
lui  $1,  4097
lw  $2,  20($1)
add  $2,  $4, $2
lui  $1,  4097
sw  $2,  0($1)               #add ort, ort, sayi5


lui  $1,  4097
lw  $4,  0($1)
ori  $2, $0, 5
bne  $2, $0, 4
break $0
div $4, $2 ..........bolümü loya kalanı HIya
mflo $2....s2ye loyu atar
lui $1, 4097
sw $2, 0($1)                          #div ort, ort, 5

lui  $1,  4097
lw  $4,  0($1)
ori $2, $0, 1
syscall                                  #put ort
ori $2, $0, 10
syscall
_______________________________________________________________
Öncelikle belirtmek isterimki SAL MAL'a göre yazımı daha kolay bir dildir.SAL tek satıra karşılık gelen programlar MAL'da  5-10 satıra denk gelebilir.Şimdi öreneğimizi inceleyelim

  • lui  $1,  4097 komutu 4097'nin 0x1001  karşılığını $1'e atar.
  • lw  $4,  4($1) : $1'in 4 byte ilerisindeki adresdeki değeri okuyup $4'e kaydeder.
  • lw  $2,  8($1) : $1'in 8 byte ilerisindeki adresdeki değeri okuyup $4'e kaydeder.
  • add  $2,  $4, $2 : $4 registerı ile $2 registerını toplayıp sonucu $2 registerına yazdı.
  • sw  $2,  0($1) :$2'deki değeri $1'den 0 byte ilerideki registera(burda $1'e) yükler.                     
Yani burda işlemler bittiğinde yaptığımız şey aslında sadece 2 sayının toplanmasıdır. Gördüğümüz gibi tek satırlık SAL kodu ne kadar satırlık MAL koduna karşılık geldi. Çünkü makine diline yaklaştıkça yapacağımız işlem sayısı artmaktadır. Gene komutlarımızı yorumlayacak olursak başlangıç adresini register'a gömerek başlıyoruz(4097). Daha sonra SAL da yazdığımız tanımlamalar sırasıyla adreslere gömüldüğünden 4 byte ileriside sayi1'i 8 byte ilerisinden sayi2'yi alıp bunları işlem yapacağımız registerlara getiriyoruz. Değerlerimizi registerlarda elde ettikten sonra registerlar arasında işlem yapabiliriz. İlk toplama komutumuz bittikten sonra ikinci toplama komutu içinde aynı işlemler söz konusudur. Sadece şu detaya dikkat edelim ikinci komutta ort değerine sayi3 eklenecektir ve 3.sayiyi başlangıç adresinden 12 byte ilerden okuruz( 12($0) ) aynı şekilde 4.sayiyi 16 byte ve 5.sayiyi 20 byte ilerden okuruz. Ort değerini ise herseferinde $1'e gömdüğünden ilk toplamadan sonra ort değerlerini $1'den okur.
Şimdi toplama kısımlarını bitirdik div komutunun olduğu kısma geçelim
  • Yine aynı şekilde lui komutuyla $1'e başlangıç adresini gömdük. $4'e $1'in içeriğin yazdık $1'de ort değeri bulunuyor yani şu aşamada 5 sayının toplamı var.






Aşağıda TAL ve MAL komut kümesi var. Ne iş yaptıklarını açıklamaya çalışacağım yukarıda kodlarda bu komutları kullandım takıldığınız noktalarda komut kümesinden faydalanınız...



ADD – Add (with overflow)

Description:
Adds two registers and stores the result in a register
Operation:
$d = $s + $t; advance_pc (4);
Syntax:
add $d, $s, $t
Encoding:
0000 00ss ssst tttt dddd d000 0010 0000

İki register'ı toplar ve sonucu 1 registera yazar


ADDI -- Add immediate (with overflow)

Description:
Adds a register and a sign-extended immediate value and stores the result in a register
Operation:
$t = $s + immadvance_pc (4);
Syntax:
addi $t, $s, imm
Encoding:
0010 00ss ssst tttt iiii iiii iiii iiii

Bir register ile bir sabit veriyi toplar ve sonucu 1 registera yazar.


ADDIU -- Add immediate unsigned (no overflow)

Description:
Adds a register and a sign-extended immediate value and stores the result in a register
Operation:
$t = $s + immadvance_pc (4);
Syntax:
addiu $t, $s, imm
Encoding:
0010 01ss ssst tttt iiii iiii iiii iiii

Bir register ile bir sabit veriyi toplar ve sonucu 1 registera yazar.



ADDU -- Add unsigned (no overflow)

Description:
Adds two registers and stores the result in a register
Operation:
$d = $s + $t; advance_pc (4);
Syntax:
addu $d, $s, $t
Encoding:
0000 00ss ssst tttt dddd d000 0010 0001

İki register'ı toplar ve sonucu 1 registera yazar

Hiç yorum yok:

Yorum Gönder