AMIGA ASSEMBLER
Retro bilgisayarBu ay makina dilinde atlama ve dallanma komutlarını inceleyeceğiz. Bu komutlar JMP, JSR ve RTS'dir. Bunlardan başka şartlı dallanma ve branch olarak dallanma yapan komutlar da vardır. Onlara daha sonra değineceğiz.
İlk olarak; JMP Jmp komutu herhangi bir hafıza adresindeki makina dili programına atlamaya ve işlemcinin işleyişini oradan yapmaya yarar. Böylece programımıza bazı makina dilinde rutin seçenekleri sunup, duruma göre değişik makina dili rutinlerine atlama yaparız. Jmp komutunun işleyişini BASIC programlama dilindeki GOTO komutuna benzetebiliriz. Tabii komutu izleyen parametreler; satır numarası yerine hafıza adresi veya bir hafıza adresini gösteren herhangi bir adres registeri olacaktır.
Kullanım modları şöyledir. 1. Kullanım Modu: JMP $50000 Örnekte de görüldüğü gibi, bilgisayar bu satırdan itibaren (JMP $50000) komutları 50000'den almaya ve işleyişine oradan devam etmeye başlayacaktır.
2. Kullanım Modu: JMP (A0) İşlemci A0 adres registerindeki adresi okuyup, işleyişine o adresten devam edecektir.
3. Kullanım Modu: JMP 4 (A0) İşlemci A0 adres registerindeki adresi okuyup, artı olarak o adrese 4 ekleyip gösterilen adrese atlayacaktır.
JSR & RTS
Bu iki komut yardımı ile subrutinler yazıp işimizi daha da kolaylaştıracağız. JSR komutu ile dallanıp RTS komutu ile ana programa geri döneceğiz.
Subrutin kavramını BASIC programlamadan tanıdığınızı tahmin ediyorum. Subrutin kavramını özetlemek gerekirse kısaca; tekrarı gereken makina dili rutinlerimizi, tekrar tekrar yazmaktansa bir tane yazıp onu defalarca aynı işi yapmak üzere çağırabiliriz. Böylece hem makina dili programlarımızı kısaltmış, hem de hızlandırmış oluruz.
Bir subrutini aynı türden başka bir işi yapmak üzere de programlayabiliriz. Bu iş için rutinin amacına göre kendimize parametreler tanımlayıp aynen Amiga ROM'unda bulunan subrutinler (ROM kütüphaneleri) gibi bunların herbirini data ve adres registerlerine tanımlayıp, rutine atlamadan önce tanımladığımız bu registerlere değerleri koyup çağırarak subrutinleri mükemmelleştirebiliriz.
Makina dilindeki JSR komutu işleyiş bakımından BASIC'deki GOSUB'a ve RTS'yi de RETURN komutuna benzetebiliriz.
Dallanma komutlarının kullanım modları ve parametreleri ise şöyle olmaktadır. 1. Kullanım Modu: JSR $50000 örnekte $50000'deki makina dili alt rutinine dallanacağımızı ifade ediyoruz.
2. Kullanım Modu: JSR (A0) adres registeri olan A0'ın içeriğinde gösterilen adrese dallanılması ifade ediliyor,
3. Kullanım Modu: JSR 16 (A0) Adres registeri olan A0'ın içeriğinde gösterilen adres olan sayıya 16 daha ekleyerek, yeni çıkan adrese dallanılması gerektiği ifade edilmiş oluyor.
4. Kullanım Modu: RTS Rts komutunda, komuttan sonra hiçbir parametre yoktur. Bu komutu subrutinden çıkmaktan başka hemen hemen bütün programlarımızın sonuna, o programdan çıkmak için koyacağız.
JSR komutu parametresinde gösterilen adrese dallanmadan önce ilk olarak Stack Pointer'e (System registerlerinden bir tanesi) ana programın neresinde kalmışsa, o adresi atayacaktır. Ondan sonra gösterilen adresteki subrutine gidecektir. Ve bilgisayar nerede RTS komutunu görürse, tekrar Stack Register'inden ana programda kaldığı yerin adresini alıp oradan ana programa devam edecektir.
Subrutinlerde, ana programda kullandığımız registerlerden başka register de kullanabiliriz. Böylece subrutinlerdeki programımızda, programın işleyişinde registerler yönünden hiçbir kısıtlama olmayacaktır. Bu iş için öncelikle subrutinin başında adres ve data registerlerinin değerlerini stack registerine gönderip, rutinden çıkarken tekrar buradan registerlerin değerlerini okuyup registerlere yazmamız gerekiyor. Bu iş için ise subrutinin başına ve sonuna şu satırları eklememiz gerekiyor.
İlk başa; MOVEM.L D0-D7/A0-A6, -(A7) ve sona; MOVEM.L (A7)+, D0-D7/A0-A6 ekleyeceğiz. Şimdi yeni bir komut;
NOP
Amiga makina dilinde hiçbir iş yapmayan bir komut var mı diye sorarsanız, benden var cevabı alacaksınız. Peki hangi komut? Tabii ki cevap, NOP komutu olacaktır. Evet gerçek adı NO OPERATION olan bu komut işleme girdiğinde hiçbir şey yapmıyor. Tek yaptığı iş (gerçi ona da iş denirse) 68000 işlemcisine 4 vuruşluk zaman harcatıyor. Bilgisayar bu komutu gördüğünde hiçbir şey olmamış gibi işine devam ediyor.
Nop komutunun çalışmasını BASIC'deki REM komutuna benzetebiliriz. Fakat yine de arasında çok fark var. İlk olarak Nop komutunda, BASIC'deki Rem komutunda olduğu gibi parametre olarak yazılar yazamıyoruz. Nop komutu her zaman tek başına parametresiz olarak durmaktadır.
Şimdi diyeceksiniz ki; "Madem hiçbir şey yapmıyor. Neden böyle bir komutu icat etmişler?". Bu komut ile neler yapılabilir? Bu sorunun cevabı aslında makina dili programcısına kalıyor. Çünkü Nop komutunun görevi programa göre değişiyor. Birkaç örnek verelim.
Örneğin; makina dili rutinimizin işleyişini yavaşlatmak için kullanabiliriz. Gerçi işlemci her Nop komutu başına 4 hz harcadığı halde yine de bu yavaşlık bazı durumlarda işe yarayabilir, özellikle grafik işlemleri sırasında bazen işlemciye grafik taşıma ve scroll komutlarını aralıklı göndermek gerekebilir. O zaman aralara Nop koyarak ekran titremelerini ya da renk bozulmalarını önleyebiliriz. Gerçi 4 hz'lik başka komutlar da aynı işi yapabilir fakat Nop komutunun özelliği hiçbir registerin değerini değiştirmemesidir.
İkinci bir örnek olarak Nop komutunu, sık sık değişen rutinlerimizde, komutlar arasına serpiştirebiliriz. Böylece rutinimize yeni ekler yaparken bu Nop dolu olan byte'ları kullanabiliriz. Bu şekilde programlama tekniğini BASIC'teki aralıklı satır numaralı yazılan programlara benzetebiliriz. Tabii makina dilinde assembler derleyici kullanarak (mesela SEKA Assembler) ikinci örneğimizi saf dışı edebiliriz.
Nop komutunun tek kullanım modu vardır.
1. Kullanım Modu: NOP İşlemciye "hiçbir şey yapılmaması ve bir alt satırdaki komut ile devam etmesini" söylüyoruz.
. CMP
İşte size bol bol kullanacağınız bir komut daha. Bu komut yardımı ile bilgisayara sayıları kontrol ettirip, byte'ları birbirleri ile karşılaştıracağız.
Cmp komutunu Basic'teki IF ... THEN komut dizisine benzetebiliriz. Cmp komutunun parametrelerinden ilkinde karşılaştırılacak değerin birincisini, ikinci parametrede ise ikincisini veriyoruz.
Komut karşılaştırmayı yapıp sonucu sistem durum registerlerine yazıyor. Biz de işlemin sonucunu sistem registerlerini kontrol ederek anlıyoruz. Registerlerdeki daha doğrusu flaglardaki (bayrak ismini verdiğimiz tek bit'lik sistem registerleri) değerleri okumak için Bcc adı altında bir dizi komutlar vardır. Bu komutlar yardımı ile Cmp işlemlerinin sonuçlarını anlayıp değerlendirmelerimizi yaparız.
Daha rahat anlamak için IF komutunu CMP komutuna ve onu izleyen THEN komutunu ise Bcc'ye benzetebiliriz.
Cmp komutu mevcut üç hafıza modunda (BYTE, WORD, LONGWORD) da çalışabilmektedir.
Kullanım modları şöyledir.
1. Kullanım Modu: CMP.B #5,D0 örnekte 5 sayısı ile D0 registerinin içerdiği sayı karşılaştırılır. Sonuç sistem registerlerinden N, Z, V, C flaglarına aktarılır.
İşlemin sonucu Negatif ise negatif flag'ı olan N bayrağı 1 değerini alır. Sonuç eşit veya 0 gösteriyor ise Zero flag'ı olan Z bayrağı 1 değerini alır. İşlemin sonucunda taşma varsa Overflow bayrağı yani V flag'ı 1 olur ve toplama veya çıkarma işlemi sonucunda elde kalırsa Carry (C) bayrağı 1 değerini alır. Biz de bu bitleri Bcc komutları ile kontrol ederek sonucu elde ederiz.
System işlem bayraklarının durumlarını daha iyi anlamak için birkaç örnek yapalım.
Örnek 1: MOVE.B #1,D0 CMP.B #1,D0 Yukarıdaki iki satırlık komut dizisinde ilk komutta D0 data registerine 1 değerini atıyoruz. İkinci komutta ise D0 registerinde 1 değeri var mı onu kontrol ettiriyoruz. Bu karşılaştırmada flagların değeri şöyle olur.
X (extend) = 0 N (Negative) = 0 Z (Zero) = 1 V (Overflow) = 0 C (Carry) = 0 Görüldüğü gibi karşılaştırılan sayılar eşit olduğunda sadece Zero bayrağı bir değerini alıyor. Diğer bayraklar 0 olarak kalmaktadır.
Örnek 2: MOVE.B #10,D0 CMP.B #25,D0 Yukarıdaki ilk komutta D0 data registerine 10 değerini atıyoruz. İkinci komutta ise D0 registerinde 25 değeri ile kontrol ettiriyoruz. Bu karşılaştırmada sistem flagların değeri şöyle olur. X (Extend) = 0 N (Negative) = 1 Z (Zero) = 0 V (Overflow) = 0 C (Carry) = 1
Görüldüğü gibi karşılaştırılan sayılardan Cmp komutundaki, ikinci parametredeki sayı (Data registerine atanan sayı), ilk parametredeki sayıdan büyük olduğunda sadece Negative ve Carry bayrakları bir değerini alıyor. Diğer bayraklar 0 olarak kalmaktadır.
Örnek 3:
MOVE.B H10D0
CMP.B H5, D0
Yukarıdaki iki satırlık komut dizisinde ilk komutta D0 data registerine 10 değerini atıyoruz. İkinci komutta ise D0 registerinde 5 değeri var mı kontrol ettiriyoruz. Bu karşılaştırmada flagların değeri şöyle olur.
X (Extend) = 0 N (Negative) = 0 Z (Zero) = 0 V (Overflow) = 0 C (Carry) = 0
Görüldüğü gibi karşılaştırılan sayılardan ilki, data registerine atanan sayıdan büyük olduğunda hiçbir bayrağa etki etmiyor.
2. Kullanım Modu: CMP.W $50000,D0
$50000 hafıza adresindeki WORD değer ($50000 ve $50001 hafıza adresindeki iki byte'lık değer) D0 data registerindeki ilk iki byte ile, diğer bir deyişle ilk WORD'ü ile karşılaştırılıyor.
3. Kullanım Modu: CMP.L (A0), D1 A0 adres registerinin içerdiği adresteki LONGWORD değer D1 registerinin tamamını kaplayan LONGWORD ile karşılaştırılır. 4. Kullanım Modu: CMP.L 10 (A0), D3
A0 adres registerinin içerdiği adres değerine 10 daha ekleyip, ortaya çıkan yeni adresin gösterdiği hafıza bölgesindeki LONGWORD değer D3 registeri ile karşılaştırılır. Tabii sonuç her zamanki gibi sistem flag'larının durumlarından okunabilir.
5. Kullanım Modu: CMP.L (A0) + , D0
Mesela A0 adres registerindeki değerin $50000 olduğunu varsayalım. Bu komut işleme girdiğinde A0'ın gösterdiği hafıza adresindeki LONGWORD değer D0 registerinin gösterdiği değer ile karşılaştırılır. İşlem tamamlanıp sonuç bayraklara aktarıldıktan sonra, bilgisayar bir sonraki komuta geçmeden önce A0 registerindeki hafıza adresinin değerini LONGWORD olarak arttıracaktır. Nedeni ise komutta (A0)+ ibaresindeki + işaretidir. Yani sonuç olarak komutun icrasından sonra A0 registerindeki değer $50004 değerini alacaktır.
Fakat örneğimiz CMP.W (A0) + , D0 olsaydı; komuttan sonra A0'daki değer $50002 olacaktı. Aynı şekilde örneğimizi CMP.B (A0) +, D0 olarak değiştirirsek, komutun icrasından sonra A0 $50001 değeri alacaktır. Yani A0'ın ne kadar artacağına CMP komutunun .B, .W, .L modlarından hangisinin kullanıldığı karar veriyor.
Gelecek sayıda Bcc komutları ile sistem flag'larını nasıl test edeceğimizi ve CMP komutunun sonucunu nasıl değerlendireceğimizi öğreneceğiz. Ve ilk makina dilindeki programımızı yazıp, makina dili programcılığında ilk adımı atacağız.
