ASSEMBLER'da YENİ UFUKLAR
Retro bilgisayarSelam !!! Bu ay dergimizde yeni bir köşeye başlıyoruz. Bu köşede Assembler komutlarını öğrenmiş ve artık somut bir şeyler görmek isteyen arkadaşlara hitap edeceğim. Tabii bu arada Assembler Kursu yazı dizisini de takip etmeniz, sizin faydanıza olur.
Assembler diliyle programcılık, Amiga'da ikiye ayrılır. Bunlar, kurallı programcılık ve daha çok oyun yazanların ve cracker'ların kullandığı sınırsız programcılıktır. Nedeni de bu şekilde programlama yapan birinin sistem rutinlerini ve structure'larını bilerek kullanması gerektiğidir.
Diğer tip programcılık, bu yazı dizisinde takip edeceğimiz şekildir. Sınırsız programcılık ismini taşımasının sebebi, programcının sistem kurallarını fazla dikkate almadan direkt hardware adresleri üzerinden çalışması yüzündendir. Bu şekilde yapılan programlama, genellikle oyun, intro ve demolarda kullanılır. Bu yüzden iş programı yazmak istediğiniz zaman, sistem rutinlerini kullanmanız ve bütün sistem kurallarına uymanız gerekir. Zira böyle bir iş programı, genellikle Intuition library'sini kullanacaktır. Fakat bir oyun programı yazmak istediğinizde, sistem sınırlamaları kısa sürede sizi üzmeye başlayacaktır. Çünkü bir oyun ya da demoda library'leri kullanmaya başladığınızda hız düşecektir. Oysa library'lerin yapabildiklerini biz kendimiz yaparsak, programın hızı maksimum düzeyde olur. Fakat bu çeşit bir programlamanın da dezavantajı devamlı geliştirilen bilgisayarlardır. Çünkü her yeni modelde, sistem rutinleri biraz daha geliştirilerek hızlandırılmakta. Bu gelişen modeller de çok kuralcı bir yapıya sahipler; kural dışı bir programla karşılaştıklarında crash etme özellikleri fazla. Fakat kim bir Amiga 3000 ya da 3500 alarak bu makinada oyun oynamak ya da demo seyretmek isteyebilir?
Gelelim bu yazı dizisinde neleri nasıl anlatacağıma, ilk olarak bu yazı dizisini takip etmek isteyenlerin hiçbir bölümü kaçırmamalarını öneririm. Yapacağınız ikinci görev ise, verilen tüm örnekleri anlayıncaya kadar oturup denemeler yapmak. Zaten ben de işi mümkün olduğunca kolaylaştırıp bir sürü örnek vereceğim. Fakat yazının teorik bilgileri de bir hayli olduğundan, bazen yazıyı 2-3 defa okumanız gerekebilir. Böyle bir durumda, hemen bilgisayarı açıp Seka'yı yükleyin ve örnekleri uygulayın. Ayrıca vereceğim örneklerle sınırlı kalmak da olmaz; bu sınır-
ASSEMBLER'da
sız programlamaya ters düşer. Burada amaç, mümkün olduğunca araştırıp denemek. Bu yüzden aleti devamlı crash ettirebilirsiniz. Sorun değil, crash eden bilgisayar bozulmaz! Bazen sırf öğrenmek için de bilgisayarı crash ettirebiliriz. Fakat bunlara daha sonra değineceğim.
Yazı planı, yaklaşık şöyle olacak: »» Copper ve hardware registerlerinin tanımı ve bunlardan grafiksel amaçlı olanların kullanımı.
»» Sesle ilgili copper ve hardware registerlerinin kullanımı.
»» Disk işletim ünitesine erişim şekilleri; hem library, hem de hardware registerlerini kullanarak bilgi okuma ve yazma.
»» Port ciplerine erişim. »» En son olarak değineceğim konu da, demo ve intro teknikleri olacak. Bundan sonra artık oyun tekniklerine kısaca inmeyi düşünüyorum.
İlk olarak size copper'ı ve hardware registerlerini tanıtmakta fayda var. Zira bundan sonra, devamlı olarak bu iki terimi kullanacağız. Copper'dan işe başlayalım. Copper (COProcessER), aslında FAT AGNUS cipinin içindeki bir birime verilen isimdir. Ayrıca Fat Agnus'un içinde bir diğer birim daha vardır: BLITTER. Copper, ekran bilgilerini kontrol eden birimin adıdır. Bu birimde renk, ekran boyutları ya da bitplane kontrol kodları gibi bilgiler bulunmakta. Library üzerinden ekran açtığımızda da, library sonuçta bu copper registerlerine bilgi yazmakta. Yani ekran ile ilgili bilgilerin en son geldikleri nokta burası. Buraya gelen bilgi, anında gerekli cipi uyararak işlemin gerçekleştirilmesini sağlar. Copper registerlerinden birine bir değer yazarsak, bu başka bir birime gitmeden direkt olarak işlenir. Oysa library kullandığımızda, bir sürü atlamalar olacaktır. İlk önce, değerler kontrol edilecek ve kullanılabilirliği araştırılacaktır. Daha sonra gerekli structure'lar hazırlanacak ve bunlar bir sonraki rutine aktarılacaktır. Son olarak da, structure'lar ayrıştırılacak ve bilgiler gerekli yerlere iletilerek işlem sonuçlandırılacak. Bu arada gerekliyse daha önceden yapılan işlemin sonuçları hafızada ayrı bir structure'da saklanacak. Library'den geri döndüğümüzde, bizim de programda hata olup olmadığını kontrol etmemiz ve hata durumunda gerekli rutinlere dallanmamız gerekli. Bütün bu işlemlerin sebebi, bilgisayarın multitasking olmasından kaynaklanıyor. Aynı anda birden fazla program çalışmaktaysa, biri diğerinin bilgilerini bozmamalıdır.
YENİ UFUKLAR

Cem GENCER Bunun için de, sistem tüm kontrolü eline alarak bize kullanabileceğimiz alanları göstermekte.
Oyunlarda bu dezavantajdır. Ne de olsa bir oyun ne kadar hızlı olursa o kadar beğenilir. Hiç kimse, ekranı titreyen bir oyuna para vermek istemez. Bu yüzden biz de tüm multi-tasking'i ve işletim sistemini devreden çıkarmalıyız. Bu, hızımızı bir hayli artıracaktır. Ayrıca hızı artırmak için değişiklikler yapmamız gerekebilir. Bu bilgi taşırken büyük sorun olabilir. Bu işlemi de BLITTER adlı birime devredebiliriz. Zira bu birimin temel görevi, çok hızlı olarak bilgi taşımaktır. Yan görevleri arasında da çizgi çizmek, hafızanın belli kısmını bir değerle doldurmak ve hafızada boş bölge aramak vardır. Bütün bu işlemleri blitter bir hayli hızlı yapmakta. Bazen blitter'ın işi daha önemli olabilir ve 68000, blitter'ın işini yavaşlatabilir. Bu gibi durumlarda blitter, 68000'i bir anlık devreden çıkarma hakkına sahiptir. Blitter işini bitirince, tekrar 68000'i devreye sokacaktır. Daha ilerde blitter ile detaylı bir açıklama yapacağım. Fakat şimdilik tekrar konumuza dönelim ve hardware registerlerini açıklamaya devam edelim. Ses kontrol registerleri dışında, geri kalan tüm hardware registerleri port entegrelerine bağlıdır. Bu cipler aracılığıyla ya port bilgileri kontrol edilir, ya da disk işletim ünitesi gibi birimlere komut ve bilgi göndererek çeşitli disk işlemleri gerçekleştirilebilir. Bu gibi konuları da yazı dizisinin ilerki bölümlerinde bulabilirsiniz.
Copper da, aslında 68000 gibi çalışan bir birimdir. Bildiğiniz gibi 68000, Amiga'nın mikro-işlemcisidir. Kendisine gelen komutları değerlendirerek gerekli işlemleri yapar. Copper'ı da aslında dört komutu olan bir mikro işlemci şeklinde kabul edebiliriz. Zira copper registerlerine bilgi aktarmak için belli komutları kullanmamız gerekli. Fakat biz bu komutları Seka'da komut olarak değil de, heksadesi-
DERLEYİCİLER
mal kod olarak girmeliyiz. Bu dört komut, 68000 komutu olmadığından, Sega'da direkt kullanılamazlar. Biz yine de komutları isimleriyle inceleyeceğiz. Bu hem daha kolay, hem de akılda kalıcı olmakta.
Bu dört komut dışında copper'ın kullandığı registerler vardır. Bunlar, Amiga'nın hafızasında $dff000 adresinden itibaren sıralanırlar. Fakat copper, bunlara erişmek için $dff000'li bir adres kullanmaz; onlara direkt adresleriyle hitap eder. Aşağıdaki basit formülle direkt adresleri hesaplayabilirsiniz:
direkt adres=hafıza adresi –$dff000 Bu işi daha basit olarak yapmak için, hafıza adresinin başındaki $dff kısmını atarız. Elimizde kalan heksadesimal değer, copper içindeki direkt adrestir. Bu adresleri ilerde copper registerlerini daha detaylı olarak incelemeye başladığımızda göreceğiz.
Bu arada, bu komutları copper'a aktarabilmek için komut ve dataların heksadesimal karşılıklarını bir listeye yazmamız gerekir. Bu listeye COPPER LIST denmekte. Daha sonra da programınıza ufak bir rutin ekleyerek bu copper listesini aktif hale geçiririz; yani copper'ın bütün komut ve dataları işlemesini sağlamalıyız. Ancak bu şekilde copper, kendisine gönderilen komut ve datalar zincirini algılayabilir.
Copper listesindeki komutlar, ekran tarama ışını her ekran başına (VBLANK- Vertical BLANKing) geldiğinde copper tarafından işlenir. Ekranın tarama ışını tarafından saniyenin 60'da birinde bir defa tarandığını düşünürsek, copper listesi saniyede 60 defa işleme sokulur.
Ekran tarama ışını hem dikey, hem de yatay koordinatları için çalışmakta. Yatay tarama ışını, $00 ile $e2 arasında değer alabilir. Ekran tarama ışını karşılaştırmasında (CWAIT ve CSKIP komutlarında kullanılır) ilk bit kullanılmadığından, tarama ışını için yatay olarak 113 koordinat mevcuttur. Bu lo-res grafik modunda yaklaşık olarak 4 piksel; hi-res modu için ise 8 piksel anlamına gelmekte. Horizontal blanking işlemi, yatay $0f-$35 koordinatları arasında gerçekleştirilmekte. Blanking işlemi, tüm kullanılan registerlerin sıfırlanıp değerlerinin tekrar yazılması anlamına gelmekte. Normalde 320 piksel genişliğinde bir ekranda $04-$47 yatay koordinatları kullanılmaz. Burada sadece zemin rengi görülebilir.
Yatay tarama ışını, 256 satıra da erişebilir. Fakat normalde bir ekranda 256'dan daha fazla satır mevcuttur. Bu fazladan satırları beklemek için, ilk önce 256. satırı beklememiz gerekmekte. Burada ekran tarama ışını sıfırlanacaktır. 256. satırı (=$ff) bekledikten sonra, düşük değerli bir satır bekletirsek, bu satır 256. satırdan sonraki satırlara denk gelecektir. Ekranda bu şekilde yaklaşık 312 satır kullanılabilir.
Aşağıda dört komutun her birini binary açılımlarıyla bulabilirsiniz.
»» CMOVE komutu: 68000 komutlarında Move, bildiğiniz gibi bir yerden başka bir yere bilgi aktarmaya yarar. CMOVE da, move komutu gibidir. Bu komut yardımıyla herhangi bir copper registerine istediğiniz değeri yazabilirsiniz. Registere yazılacak data, cmove komutunun ikinci word'unda bulunur. Datanın yazılacağı register ise birinci word'da bulunmalıdır.
İlk word: bit 0: Devamlı olarak 0 değerini taşımalı, bit 1-8: Copper registerinin direkt adresi, bit 9-15: Kullanılmıyor: 0 değerini taşımalı.
İkinci word: bit 0-15: Copper registerine yazılacak bilgi.
Bu arada copper'ın direkt kullanımda $020 direkt adresinden yukarısına yazabileceğini unutmayın. Şayet Copper uyarı biti (Copper Danger Bit) set (= 1) durumda ise copper, $010-$020 adresleri arasındaki bölgeye de erişebilir. Bu uyarı biti, copper kontrol registerinde (COPCON) bulunmakta. Tekrar hatırlatayım; copper $010 direkt adresi aşağısına erişemez. Nedeni de bu registerlerin sadece okunabilir olmasıdır. Salt okunur registerler copper'ın bazı önemli bilgilerini içerir. Bunlardan bazıları, bilgi ara depolarıdır. Disk ünitesi gibi bir birimden gelen bilgi, ilk önce bu depoda kısa bir beklemeye alınır. Ardından gideceği yere otomatik olarak gönderilir. Salt okunabilir registerlere yazmaya kalkıştığınızda, bilgisayar crash edebilir!
Aşağıdaki data tablosunda copper listesi aracılığıyla belli registerlere bilgi yazmanın nasıl yapılabileceği görülebilir:
DC.W $00e0,$0002;$0e0 direkt adresine
$0002 değerini yaz.
DC.W $00e2,$1000;$0e2 direkt adresine
$1000 değerini yaz.
DC.W $00e4,$0002;$0e4 direkt adresine
$0002 değerini yaz.
DC.W $00e6,$5000;$0e6 direkt adresine
$5000 değerini yaz.
Yukardaki kısa örnek, ilk iki bitplane adreslerini tanımlamakta. Bunu $0e0-$0e6 registerleriyle (BPL1PTH, BPL1PTL, BPL2PTH ve BPL2PTL) yapmaktayız.
»» CWAIT komutu: CWAIT komutu, video tarama ışınının belli bir satıra geldikten sonra copper'ın işlem yapmasını sağlar. Bu sayede ekran oluşturulurken belli satırlarda değişik işlemleri otomatik olarak gerçekleştirebilir ve bu şekilde sistemi kandırabiliriz. Buna en basit örnek, renk registerleri kullanılarak yapılabilir. Ekranın belli satırını bekletir ve renk registerlerini o satırda tekrar tanımlarsak, ekranda iki katı fazla renk görülmesini sağlayabiliriz. Bu işlemi istediğimiz sıklıkta yapabiliriz. BEAST gibi oyunlarda çok kullanılan bu teknik sayesinde, aynı anda ekranda 32 renk mümkünken 256 renk kullanılabilmekte. Aslında her satırda renk registerlerini baştan tanımlarsak, 256 satır içinde 8192 farklı renk yaratabilmek mümkün. Fakat Amiga'nın hardware'i sadece 4096 renk kullanımına izin vermekte. Bu yine de ekranı bir hayli dolu gösterecek ve bilgisayarın hızı hiç azalmayacaktır.
Aynı işlemi, library'den yapmaya çalıştığımızı düşünelim. Her seferinde 32 renk için, bazı registerlere 32 defa değer atamamız ve daha sonra da graphics library'den renk değiştirme fonksiyonunu çağırmamız gerekmekte. Fakat yine de bu yöntemle ekranda 32'den fazla renk oluşturamayız; zira değiştirdiğimiz renkler ekranın tümündeki renkleri etkiler. Copper'da olduğu gibi belli satırlardan sonra renkleri değiştirmek library'ler aracılığıyla imkansız.
Yine konudan çok fazla açılmaya başladım; nerede kalmıştık? Evet copper, cwait komutu yardımıyla belli bir satırı bekler. Bu bekleme süresince copper devreden çıkar ve zaman harcamaz, istenen satıra gelindiğinde, copper hemen devreye girer ve cwait komutundan sonra gelen komuttan işlemeye başlar.
İlk word: copper'ın bekleyeceği koordinatı içerir, ikinci word ise, cwait komutunun kendisidir.
İlk word: bit 0: Devamlı 1 değerini taşımalı, bit 1-7: Yatay ekran tarama ışını koordinatı (HP - horizontal Position) bit 8-15: Dikey ekran tarama ışını koordinatı (VP - Vertical Position)
İkinci word: bit 0: Devamlı 0 değerinde olmalı, bit 1-7: Yatay karşılaştırma bitleri (HE - Horizontal Enable) bit 8-14: Dikey karşılaştırma bitleri (VE - Vertical Enable) bit 15: Blitter-finished-disable biti. Normalde bu bit 1 değerini taşır.
Maskeleme bitleri, copper'ın belli koordinattan beklemesini engellemek için kullanılmakta. Bu maske bitlerinden yatay karşılaştırma bitleri olanlarını, 0 konumuna getirirsek, ekran tarama ışını yatay koordinattan dikkate almayacaktır. Bu durumda ekran tarama ışınının sadece dikey koordinattan beklemesini sağlayabiliriz. Aynı şekilde dikey koordinattan kapayarak sadece yatay koordinattan da kullanmak mümkün.
Aşağıdaki örnekte copper, ekran tarama ışınının 150. satıra (=$96) gelmesini bekler.
DC.W $9601,$ff00 ;150. dikey koordi-
natı bekle, yatay koordinatlara dikkat etme.
»» CEND komutu: Cend komutu, copper listesinin sonunu belirtmek için kullanılır. Aslında Cend komutu basit bir cwait komutundan başka bir şey değildir. Ekranda hiçbir zaman ulaşılamayacak bir noktayı bekletmemiz yeterli. Bu nokta da $ff dikey, $fe yatay koordinatlarıdır. 256. satırda 254. yatay koordinatı yoktur. Bu yüzden copper bir sonraki ekranın taranmasına başlamadan önce, devamlı bekleme konumuna geçerek zaman harcamaz. Aşağıdaki satırda copper bitirme komutunun kullanımı görülmekte:
DC.W $ffff,$fffe; $ff dikey, $fe yatay
koordinatı bekle.
