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
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
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
______________________________________________________________
.datagirdi: .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
______________________________________________________________
.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
b 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.
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 + imm; advance_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 + imm; advance_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 |
Hiç yorum yok:
Yorum Gönder