Amiga Assembler

Selam Assembler meraklıları! İşte bir ay aradan sonra yine beraberiz. Geçen ay fark etmişsinizdir, artık bu köşeyi ben yazıyorum. Zira bu köşenin eski yazarı Ömer Sinan POLAT, babasının yanına Hollanda'ya gitti. Fakat üzülmeyin, gene kaldığımız yerden programlı bir şekilde ilerleyeceğiz. Ayrıca bu ay dergimizde yeni bir köşe daha başladı. Bu yeni köşede, daha gelişmiş Assembler görebilirsiniz. Her zamanki gibi Amiga ve Assembler köşesinde Intuition başta olmak üzere, library ağırlıklı program hazırlamasını öğreneceğiz. Diğer köşede ise daha çok demo ve oyun programlamaya yarayan gizli bilgileri inceleyeceğiz. Blitter, copper gibi birimlere erişmek ya da kendi kopya koruma programınızı hazırlamayı GELİŞMİŞ ASSEMBLER köşesinde açıklayacağım.

Bu arada size MasterSeka assembler derleyicisinin yeni versiyonunun (v1.75) ele geldiğini de müjdelemeden edemeyeceğim. Önümüzdeki ay, MasterSeka'yı komple tanıtacağım; zira eklenen bir sürü komut ve fonksiyon, Assembler'da daha rahat çalışmamızı sağlamakta.

Bu ay yine, window'larla uğraşacağız. Bir window'a nasıl yazı yazabileceğimizi, window içine nasıl çizgi çizeceğimizi gösterdikten sonra artık window'a gerçek grafik nasıl yüklenir, onu göstereceğim. Hemen listemizi Seka yardımıyla yazalım.

Gelelim programın açıklamasına; bu program iki ay önce yayınladığım listeye bir hayli benzemekte. Bu yüzden temel rutinleri çok kısa olarak geçiştireceğim. İlk satırlara bakınca, bsr komutu olan birkaç satır görüyoruz. Bunlardan ilki INIT-LIBS altrutinine dallanmamızı sağlıyor. Bu rutinde gerekli library'ler açılmakta ve bunların base adresleri INTBASE ve GFXBASE isimli değişkenlere kaydedilmekte. Bu arada library'leri açtıktan hemen sonra d0 register'inin içeriğini kontrol etmemiz gerektiğini unutmuyoruz. Zira bu register içeriği library rutininden döndükten sonra 0 değerini taşıyorsa, o library rutini çağrılışında hata oluştu demektir. Bu hata, genelde library rutinlerine eksik bilgi aktarıldığında ya da bilgisayarınızın hafızası dolmaya başladığında ortaya çıkar. Genelde library rutinlerinin çoğu, programa geri dönerlerken d0 register'ine bir adres ya da değer yazar. Bu bilgi çağrılan library'e göre değişir.

İkinci bsr satırı INITSCREEN'e gitmemizi sağlamakta. Burada da screen ve window açılarak bunların RastPort'ları birbirine bağlanmakta. Bu arada sonraki kullanımlar için screen ve window structure'ının hafızadaki başlangıç adresleri SCREENPTR ve WINDOWPTR değişkenlerine yazılmakta. Window'a ait bulunan rastport structure'ının adresi ise, RASTPORT değişkenine yazılmakta. Bu değişkeni az ilerde kullanacağımızdan bu çok önemli.

Bir sonraki bsr satırımız, DRAWBOXES altrutinini göstermekte. İşte burası dikkat etmemiz gereken bir altrutin. Burada çizgilerin nasıl çizildiğini göreceğiz.

İlk üç satırda d0 ve d1 register'lerini longword olarak siliyoruz. Bu şekilde, en ufak bir hatanın oluşması bile engellenir. Ardından da GFXBASE değişkeninin içeriği a6 register'ine atanmakta. Bu da Graphics library'sini aktif library yapmakta.

Hemen ardından LINES değişkeninin hafızadaki adresi d7 register'ine atılmakta ve <sub.l #COORDS,d7> satırıyla da, bu adresten COORDS değişkeninin adresi çıkarılmakta. Bu sayede iki değişken arasındaki bilginin büyüklüğünü elde ederiz. Şimdi diyeceksiniz ki, bu büyüklüğü bulmamız niye gerekliydi? Okumaya devam ederseniz, nedenini siz de anlayacaksınız.

Hemen, bahsettiğim bu iki değişkenin satırlarına bakıyoruz. COORDS label'ı aslında bir değişkeni değil, bir data tablosunu göstermekte. LINE değişkeni ise sadece adres tespiti için kullandığım gereksiz bir değişken. Aynı şekilde bu değişken byte ya da word uzunluğunda da olabilirdi. Ya da dilerseniz label'dan sonra hiçbir komut yazmayın. Ne de olsa bize sadece label'ın adresi lazım.

COORDS label'ından sonra gelen data tablosuna bir göz atalım; buradaki tüm bilgiler word olarak. Label isminden de anlayacağınız gibi, bunlar x ve y koordinatları.

Her neyse, nerede kalmıştık? İki label adreslerini birbirinden çıkarınca, bu iki label arasındaki data tablosunun uzunluğunu elde ederiz. Bundan sonraki satır ise, bize koordinat çiftlerinin kaç adet olduğunu hesaplar. Aslında bizim burada iki defa ardarda, <divu #2,d7> komutunu kullanmamız lazımdı. Neden mi iki defa divu kullanıyoruz? İlki, data tablosunda kaç word olduğunu bulmamızı sağlayacaktır

(unuttunuz mu? bir word=iki byte.) İkinci divu ile, data tablosunda kaç çift sayı olduğu bulunacaktır. Data tablosunda ardarda gelen her iki sayı, bir ekran koordinatını temsil etmekte. Bu değerler noktanın x ve y eksenleri üzerindeki yerlerini belirler.

Programımıza tekrar dönelim. d7 registerine tabloda kaç çift koordinat olduğunu hesaplattırıp yazmıştık. Fakat bir sonraki satırda, bu sayıyı bir azaltıyoruz. Bu, biraz ilerde kullanmış olduğumuz dbf komutu ile yapılıyor. Bu komutun görevi, aslında iki-üç komutun görevine bedeldir. İlk önce verilen register kontrol edilerek, 0'ın altında bir değere ulaşıp ulaşmadığı kontrol edilir. Eğer register içeriği 0'ın altında bir sayıya ulaşmışsa, programa devam edilir. Aksi halde registerden hemen sonra verilen label'a atlanılır. Komutun kullanışı aşağıdaki gibidir:

DBF dx,ADRES dx, burada herhangi bir data registerini (d0-d7), ADRES ise hafıza blok diyagramında bulunan bir adresi temsil etmektedir.

lea 
COORDSPTR,a0 
move.l 
(a0).a0

Geliyoruz LP label'ına. Burada COORDSPTR label'ının hafızadaki adresi a0 adres registerine atılmakta ve hemen ardından bu adreste bulunan değer, yine a0 registerine aktarılmakta. Program listemizde COORDSPTR değişkenine bakarsak, bu değişkenin COORDS data tablosunun başını gösterdiğini görürüz. Bu şekilde dolaylı bir yöntemle a0'ın COORDS data tablosunun başını göstermesini sağlarız. Niye dolaylı bir yol seçtiğime gelince, bunu da az ilerde anlatacağım.

move.w 0(a0),d0 move.w 2(a0),d1 Bu iki satır, data tablosundaki ilk iki word'ü (ilk x ve y koordinatın çiftini) d0 ve d1 registerlerine koyar. Buradaki adresleme şekline dikkatinizi çekmek istiyorum. Bu adreslemeye indexli ya da ofsetli

AMIGA ASSEMBLER

adresleme denmekte. a0 adresine ofset değeri kadar sayı eklenilir ve bulunan adresteki değer bir registere ya da hafızaya aktarılır. Bu komut da birkaç komuta bedel. Bunları açacak olursak :

move.w n(a0),d0'ın karşılığı aşağıdaki gibi olur:

add.l #n,a0 move.w a0,d0 sub.l #n,a0 Gördüğünüz gibi, bu çok kullanışlı bir adresleme tipi; bu kullanışlılığı da hızdan tasarruf etmemizi sağlamakta. Bu adresleme şeklini burada bu kadar detaylı açıkladım; çünkü bundan sonra bu şekilde adreslemeleri daha çok kullanacağız.

Son olarak RASTPORT değişkenini a0 registerine atarak, jsr satırı sayesinde de gerekli library fonksiyonunu çağırıyoruz. (jsr -240(a6)). Ha, bu arada a0 registerinin içeriğini saklamamızda fayda var; çünkü büyük bir olasılıkla çağırdığımız library, bu register içeriğini silecektir. Çağırdığımız library rutinine gelince; bu grafik kursorunu d0 ve d1 registerlerinde belirtilen koordinata götürecek olan library fonksiyonudur. Grafik kursoru normalde gözükmez; fakat işlevi büyüktür. Bunun sayesinde ekranın istediğimiz yerine yazı yazar, nokta koyar ya da çizgi çizebiliriz. Bu, aynı kalemle çizim yaparken kalemi çizimin başlangıç noktasına götürme işlemi gibidir.

move.w 4(a0),d0 move.w 6(a0),d1 move.l RASTPORT,a1 jsr -246(a6) Bu satırlar, deminkilere çok benzemekte. Fakat burada ikinci koordinat çiftini registerlere atıyoruz ve başka bir library fonksiyonu çağırıyoruz. Bu sefer kullandığımız fonksiyonun adı DrawLine ve çizgi çizmeye yarıyor. Demin incelediğimiz Move ile grafik kursorunu yerleştirdikten sonra DrawLine'ı çağırırsak ekranda bir çizgi çizilir. Bu çizginin başlangıç koordinatı, Move fonksiyonunda kullandığımız noktadır. Bitiş noktasını ise DrawLine fonksiyonunda kullanılan değerler ikilisi belirlemekte.

Hemen sonraki satıra bakıyoruz; burada COORDSPTR değişkenine 8 değeri eklenmekte. Bunun sebebi, bir sonraki koordinat çiftini kullanmak isteyişimiz. Eğer LP label'ından sonra kullandığımız dolaylı adreslemeyi kullanmasaydık ve aşağıdaki gibi satırlar yazsaydık (COORDSPTR değişkeni de kullanılmıyor!) bakalım neler olurdu?

move.l     #n,d7 
LP:
lea 
COORDS,a0 
. 
. 
. 
add.l       #8,COORDS 
dbf 
d7,LP 
Böyle bir programlama sayesinde data 
tablosundaki bilgilere zarar gelecekti. Di- 
ğer bir aksayan noktayı da programdaki

döngüye bakınca görebiliriz. Bu şekilde bir rutin yazsaydık, data tablosundaki diğer değerlere ulaşmamız, bir hayalden öteye gidemezdi. Ne de olsa her seferinde döngü tekrarlandığında, data tablosunun başlangıç adresi a0 registerine yazılacaktı. Bu da döngünün en önemli fonksiyonunu iptal ederdi. Her neyse açıklamamıza devam edelim; incelediğimiz altrutinin en son satırında d7 kontrol edilerek gerekli yere dallanılmakta. Döngü bitmişse (d7'nin içeriği negatif bir değere ulaşmışsa), ana programa geri dönülmekte.

Ana programda kaldığımız yerden devam edelim; bir sonraki satırımız sayesinde yazı yazma rutinine dallanıyoruz. Burayı da açıklamadan geçiyorum; ne de olsa bildiğimiz bir şey.

Ana programda bundan sonraki kısım ise, hepinizin geçen aydan tanıdığı EVENT rutinine dallanış ve duruma göre dallanma. Burada yine WINDOWCLOSE gadget'ını kontrol ediyoruz ve bunu klikleyip çıkış rutinine geçiyoruz.

Eh, bu ay da buraya kadar gelebildim. Artık gelecek ay daha zevkli bir konu olan window içinde grafik göstermeye geçeceğim.

Gelecek sayıda görüşmek üzere hoşça kalın ...

*********************************** 
** 
AMIGA DÜNYASI 
** 
** 
ASSEMBLER KURSU 
** 
** 
INTUITION LIBRARY 
** 
** 
WINDOW EXAMPLE 
** 
** 
ÖRNEK 17.1 
** 
************************************** 
START:
movem.l    d0-d7/a0-a6,-(sp)
bsr.s 
INITLIBS 
bsr.L 
INITSCREEN 
bsr.L 
DRAWBOXES 
bsr.L 
PRINTTEXT
EVENTWAIT:
move.l       WINDOWPTR,a0 
bsr.L 
EVENT
cmpi.l        #$200,d4 
beq.s 
ENDALL 
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) 
CLOSE 1:
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
INITLIBS:
move.l 
4,a6 
lea 
INTNAME,a1 
clr.l 
d0 
jsr 
-408(a6) 
beq.s 
EXIT1 
move.l 
d0,INTBASE
lea 
GFXNAME,a1 
clr.l 
d0 ' 
jsr 
-408(a6) 
beq.s 
EXIT2 
move.l 
d0,GFXBASE
rts
INITSCREEN:
move.l 
INTBASE,a6 
lea 
NEWSCREEN,a0 
jsr 
-198(a6) 
beq.s 
CLOSE 1 
move.l 
d0,SCREENPTR 
move.l 
SCREENPTR,a0 
dd.l 
#$54,a0 
move.l 
a0,RASTPORT
move.l 
INTBASE,a6 
lea 
NEWWINDOW,a0 
jsr 
-204(a6) 
beq.L 
CLOSE2 
move.l 
d0,WINDOWPTR
rts
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 
jsr 
-378(a6) 
rts
DRAWBOXES:
clr.l 
d0 
clr.l 
d1
move.l 
GFXBASE,a6 
move.l 
#LINES,d7 
sub.l 
#COORDS,d7 
divu 
#4,d7 
sub.l 
#1,d7
LP:
lea 
COORDSPTR,a0 
move.l 
(a0),a0
move.w 
0(a0),d0 
move.w 
2(a0),d1 
move.l 
a0,DEPO
move.l 
RASTPORT,a1 
jsr 
-240(a6)
move.w 
4(a0),d0 
move, w 6(a0),d1 
move.l 
RASTPORT,a1 
jsr 
-246(a6)
add.l 
#8,COORDSPTR
dbf 
d7,LP
rts 
PRINTTEXT:
clr.l 
d0 
clr.l 
dl
move.l 
GFXBASE,a6 
move.l 
RASTPORT,al 
move.l 
#97,d0 
move.l 
#220,d1 
jsr 
-240(a6)
move.l 
RASTPORT,a1 
move.l 
#TEXT,a0 
move.l 
#[TEXTEND-TEXT-l],d0 
jsr 
-60(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 
NEWSCREEN:
dc.w 
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 
dc.l 
WINDOWTITLE: 
SCREENPTR:
dc.l 
0,0 
dc.w 
640,256,640,256,15 
WINDOWTITLE:
dc.b 
'AMIGA DÜNYASI 
SAYI' 
dc.b 
'17 ASSEMBLER' 
dc.b 
' KURSU ÖRNEK ' 
dc.b 
'PROGRAMI 17.1 ',0 
MAINSCREENPTR:
dc.l 
0,0 
dc.w 
340,60,340,60,15 
DEPO:
dc.l 
0 
TEXT:
dc.b 
"iste window içine kutu çizimi" 
dc.b 
" ve yazma birarada.",0 
TEXTEND:
dc.l 
0 
COORDSPTR:
dc.l 
COORDS 
COORDS:
dc.w 
200,75,400,75 
dc.w 
400,75,400,175 
dc.w 
400,175,200,175 
dc.w 
200,175,200,75
dc.w 
100,50,200,50 
dc.w 
200,50,200,100 
dc.w 
200,100,100,100 
dc.w 
100,100,100,50
dc.w 
400,50,500,50 
dc.w 
500,50,500,100 
dc.w 
500,100,400,100 
dc.w 
400,100,400,50
dc.w 
100,150,200,150 
dc.w 
200,150,200,200 
dc.w 
200,200,1U0,2U0 
dc.w 
100,200,100,150
dc.w 
400,150,500,150 
dc.w 
500,150,500,200 
dc.w 
500,200,400,200 
dc.w 
400,200,400,15a
LINES:
dc.l 
0