AMIGA ASSEMBLER

Selam Assembler'cılar!.. Geçen ay hatırlarsanız intuition text rutinlerini açıklamış ve intuition'un window'lara kazandırdığı özelliklerden bazılarını incelemiştik. Bu ay ise geçen ay incelediğimiz message port'a biraz detaylı olarak bakacağız.

İsterseniz message port'un ne olduğunu kısaca izah edeyim. Amiga Intuition sistemini hazırlayanlar, sistemin herkese açık şekilde olmasına dikkat etmişler. Bunu da, exec ve intuition işletim sistemini parçalara ayırarak halletmişler. Bunun yararı, her bir parçanın gerektiğinde başına buyruk çalışabilmesi. Ama her biri gerektiğinde diğer birimlerden bilgi alabilmeli. Çünkü ne kadar birbirlerinden ayrı çalışsalar da, birbirlerini rahatsız etmemeleri gerekmekte. Bunu toplumda yaşayan insanlara benzetebiliriz. Her insan başkalarını rahatsız etmediği, onların haklarına tecavüz etmediği sürece özgürdür. Aynı şekilde intuition'da değişik işlemleri gören birimler de diğer birimlerin işlevlerini engellemedikleri sürece istediklerini yapabilmektedirler.

Her bir birimin bir diğerini rahatsız etmemesi için birbirleriyle belli bir şekilde komünikasyon sağlamaları gerekir. Birimler bu komünikasyonu da mesaj port'u adını verdiğimiz ayrı bir birim yardımıyla yapmaktadırlar. Bu mesaj port'unu da birçok sahibi olan bir posta kutusuna benzetebiliriz. Posta kutumuzun sahipleri intuition ve exec işletim sistemlerinin parçalarıdır. Bunların arasında klavye kontrolü, port kontrol birimi ve disk kontrol birimi gibi bir sürü birim var. Diğer bir birime mesaj göndermek isteyen birim, mesajını paketleyerek mesaj portuna bırakır. Tabii bu mesajın üzerinde kimden geldiği, kime gideceği ve boyutu da kayıtlıdır. En son olarak da mesajı gönderen birim mesaj port kontrol birimine bir mesaj bırakıldığını ve bunun kime gideceğini bildirir. Bu sayede her seferinde doğru mesajların doğru birimlere dağıtılması sağlanır. Mesaj artık yeni sahibini mesaj port'unda beklemektedir. Birimlerin her biri belli zaman aralıklarıyla posta kutusunu (mesaj portunu) kontrol ederek, kendilerine mesaj bırakılmış mı diye bakarlar. Kendilerine mesaj varsa hemen bunu alırlar ve mesaj portu kontrol birimine de kendilerine gönderilmiş olan mesajı aldıklarını belirtirler. Daha sonra da aldıkları mesajı gerektiği şekilde işlerler ve gönderen birime mesajın alındığına dair bir teşekkür notu (yine bir mesaj) gönderirler.

Nasıl, pek de zor değilmiş değil mi? Şimdi gelelim bu anlatılanları gerçekte oldukları gibi görmeye... Zaten işin en zevkli kısmı da bu.

ÖMER SİNAN POLAT

Bir mesajı nasıl göndereceğinizi bildikten sonra Amiga'nın exec ve intuition'u ile yapamayacağınız şeyler yoktur. Evet, tüm işlemler sonuçta mesaj portuna bağlıdır. Ancak bu şekilde işlemlerin hepsinin düzgün ve isteğe uygun olması sağlanır. Mesaj portuyla yapılabilecek işlemler arasında klavyeden harf okuma, disketten ya da diskete bilgi aktarımı, paralel ve seri portlar yardımıyla çift yönlü bilgi aktarımı vardır. Tabii bu örnekler, Amiga'nın kendisi kadar geniş ve sonsuz. Her işlem değişik bir sürü işlemin yapılmasını sağlamakta. Fakat biz artık o kadar derinlerini incelemeyeceğiz; zira öyle bir işe kalkışsak, yazı dizimiz daha en az 3-4 sene rahatlıkla uzayabilir.

Yukarıda da belirttiğim gibi artık mesaj portunu kullanmaya geçebiliriz. Bunun için listesini yayınladığımız programı girmeniz gerekmekte. Bu programın yaptığı, kısaca şöyle: Bir ekran, bunun üstünde de maksimum boyutlarda bir pencere açılır. Pencere kapama ikonunu kliklediğiniz zaman, yeni bir pencere çıkarak emin olup olmadığınızı sorar. Burada biraz daha güzel bir teknik kullanarak gadget kullandım. Gadget'ları daha ileride detaylı olarak göreceğiz; fakat merak edenler yine de aşağıdaki kısa açıklamalardan biraz da olsa bilgi kapabilirler. Umarım bu kadar bilgi hemen aklınızı karıştırmaz; zira gadget'lar Amiga Intuition'unun en önemli özelliklerinden biridir ve oldukça karışıktırlar. Bütün programın açıklanmasına isterseniz hemen geçelim:

Start label'ı ile başlayan satırlardaki işlemleri, herhalde artık hepiniz anlamışsınızdır, graphics ve intuition library'leri açılmaya çalışılmakta ve başarı elde edildiğinde programa devam edilmekte. Eğer bu iki library'den herhangi biri değişik bir neden yüzünden açılamazsa, otomatik olarak program bitiş kısmına (duruma göre EXIT2 ya da EXIT1 rutinleri) dallanarak açılan library varsa onları kapar ve programdan çıkar. Library'ler açıldığında bunların base adresleri (hafızadaki kopyalarının bulundukları adresleri) INTBASE ve GFX-BASE isimli iki değişkene kaydedilir. Daha sonra ne zaman bu library'lerden birini kullanmak istiyorsak, onun base adresini a6 register'ına atmamız yeterli olacak. Bu sayede her seferinde library'i açma zahmetinden de kurtuluruz. Ayrıca bir library üst üste açılmaya kalkışıldığında, her seferinde hafıza giderek azalacaktır, zira library'ler açıldıktan sonra kapanana ya da bilgisayar reset'lenene kadar hafızada yer kaplayacaklardır. Programımıza kaldığımız yerden devam edelim. Deminki teknikle screen ve window'umuz da açılmakta. Bu tekniği bundan sonra devamlı kullanmanızı tavsiye ederim. Ancak bu sayede programınızın %100 hatasız çalışacağından emin olabilirsiniz. Hata çıksa bile, bu library ya da screen açılamadı gibi basit bir hata olmaz. Assembler'a başlarken birçok arkadaşımın ve benim başımıza gelen en büyük sorun buydu. Uzun ve detaylı bir program hazırlarız ve bunu çalıştırmaya kalkıştığımızda hata çıkar ve aklımıza hemen en uğraştırıcı kısımlarda hata olduğu gelir. Oysa genelde hafıza dolduğundan (library kapama alışkanlığımız daha yoktu) yeni bir library ya da window açılamamakta ve bizi saatlerce uğraştırmaktaydı.

Screen ve window açıldıktan sonra, bir rast-port'u screen'e tanımlıyoruz. Window ve screen adreslerini de bu arada bir değişkene koymayı unutmuyoruz. Bu, bize programdan çıkışta window'u tekrar kapayabilmek için gerekli. Tabii yine bir hata olduğunda program bunu algılayacak ve duruma göre CLOSE 1 ya da CLOSE2 isimli alt rutinlere dallanacak. EVENTWAIT isimli rutin, tüm işlemimizi yapan kısım; burada devamlı window'un kapatma ikonu kontrol edilmektedir. İlk önce a6'daki adresi bir değişkene koyuyoruz. Ardından;

move.l windoprt,a0 satırı ile işlem kontrol rutini için ön hazırlığımızı yapıyoruz. Bu rutin yardımıyla, istediğimiz herhangi bir window'da önemli bir işlem gerçekleştirildi mi diye kontrol edebiliriz. Bunun için ilk önce window'umuzu gösteren pointer adresini, a0 register'ına atamamız gerekli. EVENT rutini, adresi verilen window'a ait bilgileri kontrol ederek bir işlem yapılıp yapılmadığını kontrol eder ve işlemin niteliğine göre bir değeri d4 değişkenine koyar. Biz de window pointer'ımızı a0'a yerleştirdikten sonra, 'bsr EVENT' satırı yardımıyla bir işlem gerçekleştirildi mi diye kontrol ediyoruz. Rutinden geri dönüşte DEPO değişkeninin içeriğini tekrar yerine, yani a6 register'ına koyuyoruz. Artık sırada d4 register'ının içeriğini kontrol etmek ve buna göre bir işlem yaratmak var.

AMIGA ASSEMBLER

geldi. Eğer d4 register'ının içi boşsa, herhangi bir işlem gerçekleştirilmedi demektir ve otomatik olarak EVENTWAIT rutinini başına dönülür. Bu sayede sadece bir işlem gerçekleştiğinde, window kapama ikonu klik edildiğinde programdan çıkabiliriz. Bu arada geçen ay yayınladığımız IDCMP flag'ları tablosunun tamamını ayrıntılı olarak tekrar yayınlıyoruz. Bunlar, her window'da kontrol edilebilecek işlemlerdir. Yanlarındaki değerler de bunların IDCMP kodlarıdır. EVENT rutini çıkışında d4 register'ındaki değer, bu değerlerden biri ya da sıfır olmakta. Değere bakarak bu şekilde window üzerinde ne tip bir işlem yapıldığını belirleyebiliriz.

$0000001 - SIZEVERIFY - Window boyutları değiştirilmeye kalkışılırsa (boyut değiştirme ikonuna klik edildiğinde) bu kod gönderilir.

$0000002 - NEWSIZE - Window boyutları değiştirildiğinde bu kod gönderilir.

$0000004 - REFRESHWINDOW - Window içeriği değişik nedenlerden bozulmuşsa ve yenilenmesine (refresh) gerek varsa bu kod gönderilir. Window içeriği, window'u bir yerden başka bir yere taşırken bozulabilir. Bu gibi durumlarda, eğer window sisteme ait bir window ise Exec ve Intuition otomatik olarak bu window'un içeriğini refresh ederler. Fakat kullanılan window, sizin yarattığınız bir window ise bu işlemi siz gerçekleştirmelisiniz. $0000008 - MOUSEBUTTONS - Mouse tuşuna basıldığında bu kod gönderilir. $0000010 - MOUSEMOVE - Mouse pencere içinde yer değiştirirse, bu kod gönderilir. $0000020 - GADGETDOWN $0000040 - GADGETUP - Bu iki kod, window içindeki bir gadget'a klik edildiğinde gönderilir. İlk kod gadget'a basıldığında; ikincisi ise gadget bırakıldığında gönderilir. $0000080 - REQSET - Requester ile ilgili işlemlerde bu kod gönderilir (daha ilerde bu konuya detaylı ineceğiz). $0000100 - MENUPICK - Bir menü ya da alt-menü fonksiyonu seçildiğinde bu kod gönderilir. $0000200 - CLOSEWINDOW - Window'un kapama ikonu kliklendiğinde bu kod gönderilir. $0000400 - RAWKEY - Klavyeden herhangi bir tuşa basıldığında bu kod gönderilir. $0000800 - REQVERIFY - Yine requester'lar ile alakalı bir kod.

Requester'ın bekleme kodudur. $0001000 - REQCLEAR - Penceredeki son requester kapanınca bu kod gönderilir. $0002000 - MENUVERIFY - Menülerin çizilme işlemi tamamlanıncaya kadar beklenmesi gerektiğini bu kod yardımıyla algılayabiliriz. $0004000 - NEWPREFS - Preferences bilgilerinden biri hafızada değiştirildiğinde bu kod gönderilir. $0008000 - DISKINSERTED - Disket sürücüye disket takıldığında bu kod gönderilir. $0010000 - DISKREMOVED - Disket sürücüsündeki disket çıkartıldığında bu kod gönderilir. $0020000 - WBENCHMESSAGE - WorkBench, kullanıcıya bir mesaj aktarmak isterse (Please insert volume ... in any drive gibi) bu kod gönderilir. Bu durumda program tarafından WorkBench requester'ı ön plana çıkarılmalı ve kullanıcı da bu mesaja cevap vermelidir. Aksi halde program devamlı beklemede kalacaktır. $0040000 - ACTIVEWINDOW - Window, aktif hale geçirildiğinde bu kod gönderilir. $0080000 - INACTIVEWINDOW - Başka bir window'a klik edilerek o an aktif olan window pasif hale geçirilmişse bu kod gönderilir. $0100000 - DELTAMOVE - Mouse, sol tuşa basılarak hareket ettirildiğinde bu mesaj gönderilir.

Evet, IDCMP kodları bu kadar. Tabii geçen ay da öğrendiğimiz gibi bunlardan birini algılayabilmek için window tanımlama structure'ında IDCMP izin koduna istenilen kodların toplamı girilmeli.

Evet, tekrar programımıza dönelim. a6 register'ının içeriği geri verildikten sonra, artık d4 register'ını kontrol ediyoruz. Buradaki değer #$200 olduğunda (IDCMP tablosuna göre window'un kapama ikonu kliklendiğinde) GERCEKMI isimli rutine dallanıyoruz. Değer, #$200'den farklı ise (=0 olabilir, çünkü diğer kodların geçmesine window structure'daki IDCMP filtreleme kodu izin vermez), kontrol rutinimizin başına (EVENTWAIT) dönüyoruz.

Buradan sonraki kısımda, programın çıkış rutinleri bulunmakta. Bunlar, window ve screen'i kapadıktan sonra library'leri de kapar ve programdan çıkmamızı sağlar.

GERCEKMI rutini bir window açarak gerçekten programdan çıkmak isteyip istemediğimizi sorar ve duruma göre değişik yerlere dallanır. Tabii burada da yine hata kontrol rutinleri eklenmiş durumda. Burada yeni bir şeyle daha karşılaşıyoruz: Gadget'lar.

Rutine baktığımızda, bir pencerenin açıldığını ve graphics library'deki TEXT rutini (jsr -60(a6)) yardımıyla, sorunun pencereye basıldığını görüyoruz. Bundan sonraki kısımda (WATTREALLY label'ı) açılan window'un pointer'ı a0 register'ına konularak EVENT kontrol rutini çağrılmakta. Gördüğünüz gibi, bu kontrol rutini programın iki yerinde birden aynı şekilde kullanılmakta. Bu rutini dilerseniz aynen alıp kendi yazdığınız programlara da ekleyebilirsiniz.

Bu sefer kontrol ettiğimiz IDCMP kodu #$80000. Bunun anlamı INACTIVEWINDOW'dur. Eğer mouse ile window dışında bir yere klik ederseniz, doğrudan CLOSEREALLYWINDOW'a gidilir. Değerimiz #$80000 değilse diye hemen ardından bir kontrol daha yapıyoruz. Burada da #$40 değerini kontrol ediyoruz. Bu sayede mevcut iki gadget'tan birine basılıp basılmadığını algılayabiliriz. Eğer window dışına klik edilmemişse ve bir gadget'a basılmamışsa hiçbir işlem yapılmadı demektir. Bu da programın WAITREALLY label'ına geri dönmemizi sağlar.

Gadget'a klik edildiğinde bunun hangi gadget olduğunu nasıl anlayacağız? Bunun için dilerseniz gadget structure'ına bir göz atalım. Bu structure'ı bulmak için, window structure'ındaki 22. byte'dan itibaren bulunan longword'a bakınız. Bu longword, ilk gadget'ımızı gösteren bir pointer'dır. Burada gadget yoksa, 0 değeri olmalıdır. Gadget varsa, ilk gadget'ın adresi (bu durumda label'ı) burada yazılı olmalıdır. Ancak bu şekilde bir zincirleme ile sistem window'da bir gadget olup olmadığını anlayabilir.

Hemen programımızdaki ilk gadget structure'ına bakıyoruz: REALLYGADGETS: REALLYGADGET2: dc.w 21,35,68,17,0,$201,1 dc.l REALLYGADGET1 IMAGE,0,REALLYITEXT1,0,0 dc.w 1 dc.l 0 Burada hemen duruyoruz. İlk longword'de bir adres değişkeni var. Bu değer yardımıyla window'daki diğer gadget'lar da sisteme tanıtılır. Bu zincirleme bir şekilde olur. Her gadget, kendisinden bir sonraki gadget'ı gösterir. En son gadget ise hiçbir gadget'ı gösteremediğinden, bu longword 0 (sıfır) değerini alır. Bu durumda structure'ımıza göre birden fazla gadget var.

Bundan sonraki iki word'daki değerler (21 ve 35) bize o gadget'ın x ve y aksislerindeki koordinatını gösterir. Bu koordinat, gadget'ın sol üst köşesidir. Bundan sonraki iki word (68, 17) ise o gadget'ın değme bölgesinin boyutunu belirler. Gadget'ı kliklemek için, o bölgeye klik etmek gereklidir. Buradan gadget'ın boyutunun değme bölgesi boyutundan farklı olabileceğini görebiliriz. Fakat bunlar da işin detay kısımları ve bunları daha ilerde detaylı olarak göreceğiz. Değme bölgemizi gadget'ın boyutu kadar alıyoruz.

Karşımıza yine bir word olan 0 değeri geliyor. Bu, gadget özelliklerini belirleyen bir değerdir. Değerimiz sıfır olduğu için gadget'ımızın fazladan bir özelliği yok. Fakat merak edenler için aşağıda bu değer yerine koyabileceğimiz dört değer ve bunların anlamları mevcut: 0 - GADGHCOMP - Değme bölgesine klik edildiğinde bu bölge içeriği negatif görünüm alır. 1 - GADGHBOX - Değme bölgesi kliklendiğinde, bu bölge çerçeve içine alınır. 2 - GADGHIMAGE - Değme bölgesi kliklendiğinde, buradaki görüntü değişir. 3 - GADGHNONE - Değme bölgesi kliklendiğinde, hiçbir reaksiyon alınamaz.

İşte yine bu ayki köşemde yer kalmadı. Oysa daha gadget'ların structure'ını bitirmem gerekiyordu. Artık programın devamının açıklaması için, ne yazık ki bir sonraki ayı beklemek zorundasınız. Gelecek sayıda görüşmek üzere hoşçakalın.

İŞTE PROGRAM LİSTEMİZ: 
** AMIGA DÜNYASI AMIGA ASSEMBLER KURSU   ** 
** INTUITION LIBRARY - WINDOW EXAMPLE 15 ** 
*************************************************************** 
START:
movem.l    d0-d7/a0-a6,-(sp) 
move.l 4,a6 
lea       INTNAME,a1 
clr.l      d0 
jsr        -408(a6) 
beq.L   EXIT1 
move.l d0,INTBASE 
lea       GFXNAME,a1 
clr.l      d0 
jsr        -408(a6) 
beq.L   EXIT2 
move.l d0,GFXBASE 
move.l INTBASE,a6 
lea        NEWSCREEN.a0 
jsr        -198(a6) 
beq.L   CLOSE1 
move.l d0,SCREENPTR 
move.l d0,MAINSCREENPTR 
move.l SCREENPTR,a0 
add.l    #$54,a0 
move.l a0,RASTPORT 
move.l INTBASE,a6 
lea       NEWWINDOW,a0 
jsr        -204(a6)
beq.L   CLOSE2 
move.l d0,WINDOWPTR 
EVENTWAIT:
move.l a6,DEPO 
move.l WINDOWPTR,a0 
bsr.L    EVENT 
move.l DEPO,a6 
cmpi.l #$200,d4 
beq.L   GERCEKMI 
bra.s    EVENTWAIT 
ENDALL:move.l INTBASE,a6
move.l WINDOWPTR,a0 
jsr        -72(a6) 
CLOSE2:move.l INTBASE,a6
move.l SCREENPTR,a0 
jsr        -66(a6) 
CLOSE1:move.l 4,a6
move.l GFXBASE.a1 
jsr        -414(a6) 
EXIT2:    move.l INTBASE.a1
jsr        -414(a6) 
EXIT1:    movem.l(a7)+,d0-d7/a0-a6
rts 
GERCEKMI:
move.l INTBASE,a6 
lea        REALLYWINDOW.aO 
jsr        -204(a6) 
beq.s   REALLYEND 
move.l d0,REALLYWINDOWPTR 
move.l GFXBASE,a6 
move.l REALLYWINDOWPTR,a0 
move.l 50(a0),a1 
move.l #35,d0 
move.l #20,d1 
jsr       -240(a6) 
move.l REALLYWINDOWPTR,a0 
move.l 50(a0),a1 
lea        REALLYMESSY,a0 
move.l #[REALLYMESSYEND-REALLYMESSY-
1],d0 
jsr        -60(a6) 
WAITREALLY:
move.l REALLYWINDOWPTR,a0 
bsr.s    EVENT 
cmpi.l #$80000,d4 
beq.s   CLOSEREALLYWINDOW 
cmpi.l #$40,d4 
bne.s   WAITREALLY 
move.w $26(a4),d0 
cmp.w #1,d0 
beq.s   REALLYEND 
cmp.w #2,d0 
beq.s   CLOSEREALLYWINDOW 
bne.s   WAITREALLY 
REALLYEND:
move.l INTBASE,a6 
move.l REALLYWINDOWPTR,a0 
jsr        -72(a6) 
bra.L    ENDALL 
CLOSEREALLYWINDOW:
move.l INTBASE,a6
move.l REALLYWINDOWPTR,a0 
jsr        -72(a6) 
bra.L    EVENTWAIT 
EVENT:   move.l 4,a6
move.l 86(a0).a0 
move.l a0,MSGPORTADRESI 
move.b 15(a0),d1 
moveq #0,d0 
bset     d1,d0 
jsr        -318(a6) 
move.l MSGPORTADRESI,a0 
jsr        -372(a6) 
move.l d0,a1 
move.l $14(a1),d4 
move.w$18(a1),d5 
move.l S1c(a1),a4 
move.l a4,GADGETADRESI 
jsr        -378(a6) 
rts 
MSGPORTADRESI:    dc.l 0 
INTNAME:  dc.b   intuition.library ,0 
GFXNAME: dc.b   graphics.library',0 
even 
INTBASE: dc.l 0 
GFXBASE: dc.l 
0 
RASTPORT:dc.l 
0 
REALLYMESSY:
dc.b      "PROGRAMDAN ÇIKACAK MISINIZ ? ".0 
REALLYMESSYEND:
dc.b     0,0 
NEWSCREEN:     dew     0,0,640,256,1
dc.b     0,1 
dc.w     $8000,1 
dc.l 0,0,0,0 
WINDOWPTR:     dc.l 0 
NEWWINDOW:    dc.w     0,0,640,256
dc.b     0,1 
dc.l       $200,$1008,0,0,WINDOWTITLE 
SCREENPTR:      dc.l 0,0
dc.w     640,256,640,256,15 
WINDOWnTLE:
dc.b      'AMIGA DÜNYASI SAYI15 ASSEMBLER' 
dc.b      ' KURSU ÖRNEK PROGRAMI15.1',0 
REALLYWINDOWPTR:dc.l      0 
REALLYWINDOW:     dc.w     90,50,420,60
dc.b     1,1 
dc.l       $80040,$1000,REALLYGADGETS,0,0 
MAINSCREENPTR:    dc.l 0,0
dc.w     340,60,340,60,15 
REALLYGADGETS: 
REALLYGADGET1:
dc.l       REALLYGADGET2 
dc.w     21,35,68,17,0,$201,1 
dc.l       REALLYGADGET1 
IMAGE,0,REALLYTTEXT1,0,0 
dc.w     1 
dc.l      0 
REALLYITEXT1:
dc.b     3,0,1,0 
dc w     10 5 
dc.l       0,REALLYlTEXTTEXT1,0 
REALLYITEXTTEXT1:
dc.b      'Lutfen ',0 
REALLYGADGET1 IMAGE:
dc.w     -2,-1 
dc.b     3,0,1,5 
dc.l       REALLYGADGET1 BORDERVECTORS,0 
REALLYGADGET1BORDERVECTORS:
dc.w     1,0,70,0,70,18,1,18,1,0 
REALLYGADGET2:
dc.l 0 
dc.w     330,35,68,17,0,$201,1 
dc.l       
REALLYGADGET2IMAGE,0,REALLYTTEXT2,0,0 
dc.w     2 
dc.l 0 
REALLYITEXT2:
dc.b     3,0,1,0 
dc.w     125 
dc.l       0,REALLYITEXTTEXT2,0 
REALLYITEXTTEXT2:
dc.b      Asia! .0,0 
REALLYGADGET2IMAGE:
dc.w     -2,-1 
dc.b     3,0,1,5 
dc.l       REALLYGADGET2BORDERVECTORS,0 
REALLYGADGET2BORDERVECTORS:
dc.w     1,0,70,0,70,18,1,18,1,0 
DEPO:        dc.l       0 
GADGETADRESI:
dc.l      0