Amiga Assembler
Retro bilgisayarSelam 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