AMIGA ASSEMBLER

Merhaba! Bir ay aradan sonra tekrar birlikteyiz. Bu ay yine birtakım library fonksiyonlarını öğreneceğiz. Biliyorum, her seferinde library fonksiyonları öğrenmek biraz sıkıcı. Fakat bunları şimdiden öğrenirsek ilerde program yazmaya başladığımızda pek fazla açıklama yapmama gerek kalmayacak. Bu yüzden bana biraz daha sabırlı olmanızı dilemek ve hemen yeni fonksiyonlar tanıtmaya başlamak kalıyor. Bu ay tanıtacağım library fonksiyonlarını biraz daha düzenli olarak başlıklar altında topladım. Bu sayede, bir fonksiyonun açıklamasını aradığınızda daha rahat bir şekilde bulabilirsiniz. Hemen başlıyorum..

IOErr Bu fonksiyon dos library'sinde bulunmaktadır. Kullanımı da çok basit. Çağırırken hiçbir parametre gerektirmiyor. Library ofseti -132 (=-$84) olan bu fonksiyonun işlevi de hayli yararlı. Herhangi bir giriş/çıkış fonksiyonunu çağırdığınızda bir hata oluşmuşsa, IOErr fonksiyonu bu hata hakkında daha ayrıntılı bilgi verir. Library'de giriş/çıkış işlemlerini gerçekleştiren fonksiyonlar hata oluşması durumunda çağrıldıktan sonra d0 register'ine 0 yazarlar. Böyle bir durumda sizin ayrı bir rutine dallanıp burada IOErr ile hatayı algılayıp kullanıcıyı uyarmanız gerekmekte. Fonksiyon çağrıldıktan sonra d0'da hata mesajını tanımlayan bir sayı bulunur. Bu sayı 0 olduğunda hiçbir hata oluşmamış demektir. Aşağıda IOErr fonksiyonunun gösterdiği hatalar kod numaralarıyla listelenmiştir.

103 - insufficient free store: Kullanıma ayrılmış hafıza doldu. FreeMem ile hafıza boşaltın ve tekrar deneyin.

121 - file is not an object module: Çağırmaya çalıştığınız dosya çalıştırılabilir dosya (executable) değil. Kontrol edin.

202 - object in use: Başka bir task ya da program bu file'ı kullanıyor. Aynı anda çalışan diğer taskların ya da programların bu file'ı UnLock ettiklerinden emin olun. Bir dosyayı shell ya da CLI üzerinden çalıştırdığınızda da bu hata oluşabilir. Bu durumda shell/CLI'ı kapamanız gerekmekte.

203 - object already exist: Yaratmaya çalıştığınız dosya ile aynı isimde başka bir dosya diskette zaten mevcut. İsim değiştirerek tekrar deneyin.

Cem GENCER 204 - directory not found: Belirtilen isimde directory bulunamadı. Bu hatayı engellemek için ilk önce directory'nin var olup olmadığını kontrol edin.

205 - object not found: Belirtilen isimde dosya bulunamadı. İlk önce dosyanın varlığını kontrol ederseniz bu hata oluşmaz.

209 - action not known: Böyle bir işlem tanınmıyor. Saçma bir komut girerseniz bu mesajla karşılaşabilirsiniz. 210 - invalid stream component name: File ya da directory isminde geçerli olmayan bir karakter kullanılmış. Düzeltip tekrar deneyin.

211 - invalid lock: File lock'ta elde ettiğiniz lock değeri geçerli değil.

212 - object wrong type: Çalıştırmaya çalıştığınız dosyanın file tipi yanlış. Bu hata bir device ismini (mesela ram:) program ismi olarak kullanmanızda oluşabilir.

213 - disk not validated: Bilgisayar diskete bilgi yazarken disketi çıkardığınızda, o an yaratılan dosya kapanamaz. Bu durumda her disketi takışınızda sizden boot ettiğiniz disketi takmanızı ister. Böyle bir diskete yazmaya kalkıştığınızda da bu hatayı alırsınız. WorkBench ya da içerisinde Disk-Validator dosyasının bulunduğu (L directory'sinde) bir disket yardımıyla disketi tekrar düzeltebilirsiniz. Fakat son yaratmaya çalıştığınız dosya boş dosya olur.

214 - disk write protected: Disketin write protect deliği açık konumdayken diskete yazmaya kalkıştığınızda bu hata kodunu alırsınız.

215 - rename across devices: Rename işleminin device isimlerini farklı girerseniz bu hata kodunu elde edersiniz. Normalde rename işleminde farklı isim ve/veya farklı directory girilebilir. Farklı directory ismi girdiğinizde file, eski directory'den silinip yeni directory'nin içerisine yazılır. Fakat bu işlemi device'larla yapamazsınız.

216 - directory not empty: Boş olmayan bir directory'i silmeye kalkıştığınızda bu mesajı alırsınız.. İlk önce o directory içerisindeki tüm dosyaları silin, ardından directory'i silebilirsiniz.

218 - device not mounted: Verilen isimde bir device sisteme mount edilmemiş ya da takılı değil.

219 - seek error: Dos library'sinden Seek fonksiyonunu hatalı bir parametre ile çağırdığınızda bu kodu alabilirsiniz. Seek fonksiyonunu da bu ay tanıtacağımdan daha ayrıntılı bilgi için daha aşağılara bakmanızı öneririm.

220 - comment too big: Bir file'ın comment'ını (dosya notu) değiştirmeye kalkıştığınızda, not string'i izin verilenden uzun ise bu kod karşınıza çıkacaktır.

221 - disk full: Disket dolmak üzereyse ya da dolmuşsa ve bu diskete yeni bir file yazmaya kalkıştığınızda bu kodu elde edersiniz.

222 - file is protected from deletion: File project'i silmeye karşı korumalı olan bir dosyayı silmeye kalkıştığınızda bu hata kodunu alabilirsiniz.

223 – write protected: File protect'i yazmaya karşı korumalı bir dosyaya yazmaya kalkıştığınızda IOErr fonksiyonu bu hata kodunu verir.

224 - read protected: File protect'i okumaya karşı korumada olan bir dosyayı okumaya kalkıştığınızda bu kodu elde edersiniz. KickStart 1.2 ve 1.3'lerde bu protect modu daha tamamlanmadığından bu mesajı da almanız çok zor…

225 - not a dos disk: Disket sürücüsüne takılan disket DOS formatında değil.

226 – no disk in drive: Erişmeye çalıştığınız disket sürücüsünde disket takılı değil.

Delay: Bu fonksiyon da dos library'sinden. Ne işe mi yarıyor? Gayet basit, belli bir süre beklememizi sağlıyor. Bekleme süresini 1/50 saniye olarak d1'e yazmamız ve fonksiyonu -198 (=-$c6) library ofsetiyle çağırmamız yeterli.

ExNext: İşte yine bir dos fonksiyonu daha! Geçen ay öğrenmiş olduğumuz Examine fonksiyonu sadece bir directory'nin directory header'ını elde etmemizi sağlıyordu. ExNext fonksiyonu ise directory header'a bakarak burada yer alan ilk file'a ait header'ı bulmamızı sağlıyor. Bu fonksiyonu ardarda çağırdığımızda her seferinde o directory'deki bir sonraki file'a ait header'ı elde ederiz. Bu şekilde de istediğimiz directory'nin içeriğini okuyabiliriz. ExNext'in parametreleri Examine ile aynı. Filelock'u d1'e, boş fileinfoblock'un adresini de d2'ye yazıyoruz. Fonksiyonu çağırmak için kullandığımız ofset de -108 (=-$6c). ExNext fonksiyonu, directory'e ait başka file yoksa d0 register'ına 0 yazar. Tam bir directory alabilmek için ExNext fonksiyonunu, directory'deki tüm file header'ları okuyuncaya kadar tekrarlamalısınız.

Aşağıdaki kısa alt rutin directory'i okur. Rutini doğru kullanmak için başlangıçta gerekli library'leri açmalısınız. Program

AMIGA ASSEMBLER

çıkışında da yine bu library'leri her zaman olduğu gibi kapamayı unutmayın. PRTFILENAME rutininde de normalde ekrana basma rutinidir. Fakat ben bu rutini boş bıraktım. Dileyen buraya istediği ekrana basma rutinini yazabilir (CLI ekranına basmak için CON device'ını ya da graphics library'deki Text fonksiyonunu kullanarak). Ayrıca altrutin hiçbir hata kontrolü de yapmıyor. Bunu sadece bir directory'nin nasıl okunabileceğini göstermek için veriyorum.

Unutmayın, file ismi, file header'ının 8. byte'ında başlar. Bizim rutinde file isim string'inin adresi her seferinde FILENAMEADR değişkenine atılmakta.

READDIR: 
move.I 
DOSBASE,a6 
move.l #DIRNAME,d1 
move.I 
#-2,d2 
jsr 
-84(a6) 
move.l d0.LOCK
move.l 
DOSBASE,a6 
move.l 
LOCK.d1 
move.l 
#FILEINFO,d2 
jsr 
-102(a6) 
move.l 
d0,d6 
LOOP: 
move.l 
DOSBASE,a6 
move.l 
LOCK.d1 
move.l 
#FILEINFO,d2 
jsr 
-108(a6) 
tst.l 
dO 
beq 
ENDOFDIR 
move.l #FILEINFO+8,FILENAMEADR 
bsr 
PRTFILENAME 
bra 
LOOP 
ENDOFDIR: 
rts
DIRNAME: 
dc.b        "DF0:",0
FILEINFO: 
blk.l 
20,0 
FILENAMEADR: 
del 
0 
LOCK: 
del 
0

Gördüğünüz gibi, directory okumak gayet basit. Dilerseniz file isminin yanı sıra file header'daki diğer bilgilerin de (protect flag'ları, file uzunluğu, yaratılış tarihi, dosya notu gibi) ekrana basılmasını sağlayabilirsiniz.

Exit Bu fonksiyon, bir programdan ya da task'dan çıkışı sağlamaktadır. Normal rts'den farkı, istediğimiz bir değeri CLI'a programın çıkış kodu olarak aktarır. Bu kodu daha sonra CLI'dan istediğimiz gibi değerlendirebiliriz (FAIL gibi CLI komutlarıyla). Eğer Exit fonksiyonunu bir task içinden çağırmışsak task işlemi durdurulur, task tarafından ayrılan normal hafıza ve stack hafızası geri verilir. Fonksiyonun tek bir parametresi var; o da çıkışta CLI'a aktarılacak olan değer. Bu değeri d1'e yazmamız gerekmekte. Fonksiyonun library ofseti ise -144 (=-$90).

LoadSeg Normalde Amiga'da bir file'ı çalıştırmak istediğimiz zaman, CLI'dan onun ismini yazmamız yeter. ROM rutinleri otomatik olarak o file'ın hafızaya yüklenmesini ve çalıştırılmasını sağlar. Bunu yazmış olduğumuz assembler program aracılığıyla da yapabiliriz. İkinci bir programı assembler'dan çağırmak için iki yöntem mevcut. İlki DOS library'den Execute fonksiyonu. Burada çalıştıracağımız program ismini parametre olarak library fonksiyonuna aktarmamız gerekmekte. Bu yöntemin tek kötü yanı, çalışması için disketin C directory'sinde RUN komutuna gereksinim duymaktadır. Başka bir dezavantaj da bu yöntemde bazen kilitlenmeler olabilmekte. Zira hafıza tam olarak geri verilemeyeceğinden giderek dolmakta. Diğer yöntem ise LoadSeg. Bu yöntem tüm kullandığı hafızayı da geri verdiğinden dolayı en güvenilir olanı. Fakat dilerseniz şimdi biraz teorik bilgi vermek istiyorum. AmigaDOS'ta her program hunk adını verdiğimiz parçalardan oluşur. Bu hunk'lar içerisinde programın kendisi ve programa ait datalar bulunmaktadır. Hunk'ların her birine içindeki bilgiye göre isim verilir. Program kısmını taşıyan hunk'lara HUNK_CODE, data içerikli parçalara HUNK_DATA ve programın çalışması sırasında içeriği belirlenen dataların bulunduğu hunk'lara HUNK_BSS adı verilmiştir. LoadSeg, bir program dosyasını tüm hunk'larıyla yükler ve hunk listesinin bulunduğu adresi bize verir. LoadSeg ile hafızaya yüklenen bir programı çalıştırmak için fonksiyonun geri verdiği adres aracılığıyla ilk program hunk'ının başlangıç adresini bulmalıyız. Bunun için de d0'dan aldığımız değeri ilk önce 4 ile çarpmamız ve bu değere 4 eklememiz gerekmekte. Elde ettiğimiz bu değere basit bir jsr ile de yüklemiş olduğumuz programı çalıştırırız.

LoadSeg fonksiyonunun parametreleri yalnızca bir tane; o da program ismi. Program isminin olduğu string'in başlangıç adresini d1 register'ına yazmamız gerekmekte. Fonksiyonun library ofseti ise -150 (=-$96). UnLoadSeg LoadSeg ile yüklenip çalıştırılan bir program biz onu silinceye kadar hafızada kalır. Ama her bir hunk'ın adresini teker teker bulup o bölgeleri FreeMem ile serbest bırakmamız çok dolaylı bir iş olacağından, bunun yerine ROM'daki bir fonksiyon olan UnLoadSeg fonksiyonunu kullanabiliriz. Bu fonksiyon yardımıyla yüklenmiş olan hunk'ın tüm kapladığı hafıza alanları tekrar sisteme geri iade edilecektir. Bu fonksiyonun da tek parametresi var; o da segment adresi. LoadSeg'i çağırdıktan sonra d0 aracılığıyla elde ettiğimiz değeri UnLoadSeg'i kullanmadan hemen önce d1 register'ına yazmalıyız. Fonksiyonun library ofseti -156 (=-$9c).

Seek BASIC dilini kullananlar bilirler; BASIC'te bir sequential dosya açmak çok kolaydır. OPEN ve PRINT# komutlarıyla bu işi rahatlıkla yapabilirsiniz. Assembler'da bu, library kullanarak daha da kolaydır. DOS library'sindeki Seek fonksiyonu tam istediğimiz işi yapmakta; bir dosyanın istediğimiz yerini okumayı ya da yazmayı sağlamakta. Bunun için de dosyayı komple hafızaya okuyup değiştirdikten sonra da tekrar diskete yazmaya gerek yok. Seek ile file pozisyonunu başlangıçtan itibaren istediğimiz byte öteye ya da bitiş pozisyonundan itibaren istediğimiz byte kadar geriye alabiliriz. Ayrıca üçüncü bir mod ile de o an bulunduğumuz pozisyondan istediğimiz byte kadar ilerisine de gitmemiz mümkün. Fonksiyonu çağırmadan önce d1'e file handler pointer'ını (Open ile elde ettiğimiz), d2'ye de pozisyon ofsetini yazmalıyız. d3 register'ı Seek'in çalışma şeklini belirler. Başlangıçtan itibaren belli bir ofsete ulaşmak istiyorsak buraya OFFSET_BEGINNING (=-1), o anki pozisyondan itibaren belli bir noktaya ulaşmak istiyorsak OFFSET_CURRENT (=0) değerlerini yazmalıyız. Sondan geriye doğru belli bir ofset değerine gidilecekse, kullanılacak değer OFFSET_END'in karşılığı olan 1 olmalıdır. Fonksiyonu çağırmak için kullanacağımız library ofseti, -66 (=-$42). Seek'i çağırdıktan sonra d0'da elde ettiğimiz değer fonksiyonu çağırmadan önceki file offset pozisyonudur. O anki file pozisyon offset'ini öğrenmek için Seek'i OFFSET_CURRENT modunda ve 0 offset değeriyle çağırmanız yeterli olacaktır. Bir file'ın sonuna gitmek içinse OFFSET_END modunu 0 offset değeriyle kullanmalısınız. Aynı şekilde 0 offset değeriyle MOD-

DERLEYİCİLER

OFFSET_BEGINNING kullanırsanız, file'ın başına erişebilirsiniz.

Seek fonksiyonunda file pozisyon ofseti, file uzunluğunu aşacak konuma gelmişse DOS üzerinden Seek Error mesajı gönderilir. Bu mesajı algılamak için Seek'in geri verdiği değeri kontrol etmeniz gerekmekte. Bu değer -1 ise IOErr fonksiyonunu kullanarak hatanın ne olduğunu öğrenebilirsiniz.

DateStamp Bu fonksiyon, sistem saati ayarlanmışsa, saatin o anki içeriğini bize bildirir. Fonksiyonu çağırmak için 3 longword'luk boş bir alanın başlangıç adresini d1 register'ına vermeliyiz. Fonksiyon DOS library'sinde ve çağırmak için kullanacağımız ofset de -192 (=-$c0). Fonksiyonu çağırdıktan sonra boş olan 3 longword, tarih ve saati bildirir. İlk longword, 1 Ocak 1978 tarihinden itibaren geçen gün adedini bize verir. İkinci longword ise saat 00:00'dan itibaren geçen dakika adedini verir. Son longword ise en son dakika artırımından sonraki clock adedini bize verir. Bu değeri de 50'ye böldüğümüzde saniyeyi öğrenmiş oluruz. Aşağıdaki ufak rutin bize tarih ve saati alışık olduğumuz biçimde verir.

GETCLOCK: 
move.l       DOSBASE,a6 
move.l       #ADRES,d1 
jsr 
-192(a6)
lea 
ADRES.a0 
move.I 
0(a0),d0 
divu 
#365,d0 
move.I 
d0,d1 
swap 
d1 
and.I 
#$ffff,d0 
and.I 
#$1ff,d1 
move.I 
d0,d2 
divu 
#4,d2 
move.I 
d2,d3 
swap 
d3 
and.l 
#$ffff,d2 
and.I 
#7,d3 
sub.l 
d2,d1 
add.I 
#1978,d0 
move.l 
d0,YIL
move.I 
#-1 ,d5 
clr.l 
d6 
lea 
AYTABLE.a1 
AYLOOP: 
add.l 
#1 ,d5 
add.l 
(a1,d5),d6 
cmp.l 
d1,d6 
bgt 
AYLOOP 
sub.l 
#1,d5 
move.l 
d5,AY
sub.l 
(a1,d5),d6 
sub.l 
d6,d1 
move.l 
dl.GUN
move.l 
4(a0),d0 
divu 
#60,d0
move.l 
d0,d1 
swap 
d1 
and.l 
#$1f,d0 
and.l 
#$3f,d1 
move.l 
d0.SAAT 
move.l 
d1, DAKİKA
move.l 
8(a0),d0 
divu 
#50,d0 
move.l 
d0.SANIYE
rts
ADRES: 
del 
0,0,0 
SANİYE: 
del 
0 
DAKİKA: 
del 
0 
SAAT: 
del 
0 
GUN: 
del 
0 
AY: 
del 
0 
YIL: 
del 
0

Eh, bu aylık da ne yazık ki yerim doldu. Fakat bir hayli teorik ve pratik bilgi kapmış olduğunuzu umarım. Pratiğinizi geliştirmek için verdiğim tüm fonksiyonlarla ilgili ufak tefek örnekler yapmanız faydalı olur. Hoşçakalın...