ASSEMBLER'da YENİ UFUKLAR

Evet, geçen ay kaldığımız yerden devam ediyoruz. Bu bölümde geçen ay anlattığım CWAIT, CMOVE ve CEND komutlarının pratikte nasıl kullanıldıklarını göreceğiz. Bu komutlar 68000'in komutları arasında değiller. Bu yüzden de bu komutları programımızda kullanmaya kalkıştığımızda, hex karşılıklarını programımıza data satırları olarak eklemeliyiz. Bunu da ya direkt dc.b kullanarak, ya da makro kullanarak yapabiliriz. Biliyorsunuz, MSeka'nın makro özelliği sayesinde dilerseniz yeni komutlar yaratabilirsiniz. Makroları daha tanımayanlara, geçen ayki Master-Seka yazısını okumalarını öneririm. Unutmayın, makroları her zaman source'unuzun başına girmelisiniz. Her neyse, gelelim kendimize gerekli olacak olan üç komutu yaratmaya. CWAIT: MACRO IF NARG=2 dc.b ?2,?1,$ff,$fe ELSE FAIL ENDM CMOVE: MACRO

IF NARG=2 
dew    ?2,?4 
ELSE FAİL 
ENDM 
CEND: 
MACRO 
IF NARG=0 
dew    $fffffffe 
ELSE FAİL 
ENDM 
Evet, üç makromuz da hazır. Peki bunları nasıl kullanacağız? 
Gayet basit, normal komutları nasıl kullanıyorsak aynı şekilde. 
İşte aşağıda birkaç ufak örnek:
CMOVE   $0f00,$0180 
CWAIT  $07,$40 
CWAIT  $01,$f0 
CMOVE   $1200,$0100 
CEND 
Bunları hemen MSeka'da yazmaya kalkışmayın. Bir sonuç el- 
de edemezsiniz. Dilerseniz şimdi bu üç yeni komutumuzu nasıl* 
kullanacağımızı görelim:

* CMOVE <data>,<reg>: Bu komut yardımıyla herhangi bir copper register'ına istediğimiz değeri yazabiliriz. Komutu oluşturan makroya bir göz atarsak, komuta ikiden farklı sayıda parametre girersek MSeka'nın bu source'u FAIL komutu yüzünden compile etmeyeceğini görürüz. Makro içerisinde gelen parametreleri neden ters yerleştirdiğimi anlatmayacağım. Zaten geçen ayki yazıyı dikkatli okuyup öğrenenler bunu bilirler.

* CWAIT <x>,<y>: Tarama ışının istenilen ekran koordinatına gelmesi beklenir. Bu ekran komutu, iki byte olarak x, y koordinatını

"" şeklinde girmelisiniz. x koordinatı her zaman çift sayı olmalıdır; aksi halde programınız hatalı çalışır. Burada da parametreleri makroda ters yerleştirdim. Bu komut da, aynı bir önceki gibi, ikiden farklı parametre sayısında hata mesajı verilmesine sebep olur.

* CEND: Copper listesinin sonunu belirler. Parametre kullanılmamalıdır, aksi halde FAIL hata mesajını verir.

Evet, bu komutları programımıza nasıl ekleyeceğimize birazdan geleceğim. Fakat ilkönce bir şeyi açıklığa kavuşturmak istiyorum. Bu, copper listemizi copper cipine nasıl aktaracağımız. Burada sistem rutinlerinden de faydalanabiliriz, copper registerlarından da. İlki kullanılacağı zaman graphics.library'nin açılmış olmasını gerektirir. Oysa çok fazla hafıza harcayacak programlarda bu bir dezavantajdır, ikincisinde ise copper listesini set edebiliriz, yani copper cipine listemizi tanıtabiliriz. Fakat programdan çıkış olduğunda eski copper listesini aktif hale getirmek için graphics.library'yi başlangıçta mutlaka açmalı ve o anki copper'ın adresini saklamalıyız. Ancak bundan sonra copper listesini set eder ve programdan çıkışta da yine graphics.library'yi kullanarak eski copper'ı aktif yapabiliriz. Bunlardan hangisini kullanacağınız artık size kalmış; benden açıklaması. Ben bütün örnek programlarda ilkini kullandım.

* Copper listesinin library yardımıyla set edilmesi: Bunun için graphics.library'deki GFXBASE structure'ını kullanacağız. Bu structure'daki gereksiz kısımları atlıyorum. İsteyen assembler köşesini takip ederek structure açıklamalarını inceleyebilir. GfxBase structure'ı, graphics.library açıldığında base adresinden sonrasında bulunan structure'dır. GfxBase structure'ında 50. (=$32) ofsetteki long-word, aktif olan copper'ın adresini gösterir. Programımızda biz sadece bu adresteki bilgiyi longword olarak bir değişkene (örneğin SysCopper) kopyalarız. Ardından da 50. ofsetteki longword'e kendi copper listemizin başlangıç adresini yazarız. Bunu da ister label kullanarak, istersek de direkt adres yazarak yapabiliriz. Direkt adres yazarken, copper listesinin bu adreste bulunduğunu garantilemeliyiz. Bunu da, source'ta copper listesinden önce ORG ve LOAD komutlarını yazarak ya da copper listemizi word word o adresten sonrasına kopyalayarak yapabiliriz. Eh, bir hayli opsiyon var değil mi? Bunlardan en basiti, hiç kuşkusuz label kullanarak. Aşağıdaki satırları programınıza eklerseniz, copper'ı hiç sorun olmadan set ve reset edebilirsiniz, move.l GfxBase,a6 ; graphics.library başlangıcı move.l 50(a6),SysCopper ; sistem copper'ını saklar, move.l #Copper,50(a6) ;bizim copper'ı aktif yapar. .

Bunun bir de çıkışı var. Çıkış rutininize de şu satırları ekleme- 
niz gerekmekte: 
move.l    GfxBase,a6 
; graphics.library başı. 
move.l    SysCopper,50(a6) ; Eski copper'ı aktif hale getirir.

* Copper listesinin copper yardımıyla set edilmesi: Bu yöntemde listemizi set etmek için copper'ı kullanıyoruz. Copper register'larında iki register bu işimizi görmekte. Bunlardan ilki olan $0080 ve $0082'ye copper listemizin adresini yazıyoruz. Hardware Reference Manual kitabında bu adreslerin ismi COP1LCH ve COP1LCL olarak geçmekte. Buradan adresimizin üst word'ünün $0080 register'ına, alt word'ün de $0082'ye yazılacağını anlayabiliyoruz. Fakat bunu daha kısa yapmanın yolu, adresimizi $0080 register'ına direkt longword olarak yazmamız. Bu şekilde zaten üst longword $0080'e, alt longword'da $0082'ye gidecektir. Eee, daha ne bekliyoruz? Copper listemizin adresini yazdık; fakat copper cipi, bu adresin aktif copper olarak kullanılmasının da onaylanmasını ister. Bunu da $0088 register'ına herhangi bir değer yazarak yapabiliriz. Bu register'ın ismi COPJMP1. Register bir strobe register'ı. Bu, buraya yapılacak herhangi bir işlemin copper'ı aktif hale getireceğini tanımlar, move.l #Copper,$dff080 ; Copper adresini yaz. clr.w $dff088 ; Copper cipine yeni listeyi bildir. Copper'ı aktif hale getirdik. Peki programdan çıkmak istediğimiz zaman nasıl eski copper'ı set edeceğiz? Bunun için demin de belirttiğim gibi programımızın başında eski copper adresini sak-

ASSEMBLER'da YENİ UFUKLAR

Cem GENCER lamamız gerekli. Bu yüzden az yukarıdaki satırların başına bir de şu satırları eklemeliyiz:

move.l GfxBase,a6 ; graphics.library başlangıcı move.l 50(a6),SysCopper ; sistem copper'ını saklar. Programın çıkış rutinine geldiğimizde de aşağıdaki satırları eklememiz gerekmekte:

move.l GfxBase,a6 ; graphics.library başı. move.l SysCopper,50(a6) ; Eski copper'ı aktif hale getirir. Sizin de anlayabileceğiniz gibi iki yöntem arasında tek fark, copper'ın nasıl set edildiğinde yoğunlaşıyor. Geri kalan satırlar tümüyle aynı.

Copper listemizi nasıl aktif hale getirip kapayabileceğimizi böylece öğrenmiş olduk. Şimdi gelelim esas konumuz olan copper listemizde yukarıda bahsettiğim komutların kullanımına. Bunun için vermiş olduğum listeye bakmanız yeterli. Listenin en sonunda COPPER label'ından sonra gelen kısım tümüyle bizim yeni copper listemiz. Dilerseniz burayı hemen bir inceleyelim.

Copper listesinin ilk satırındaki komut, $5200 değerini $0100 register'ına atıyor. Bunun anlamı mı ne? $0100 register'ının ismi BPLCON0. Bu register yardımıyla ekranın bazı önemli bilgilerini tanımlayabiliriz. $5200'ün anlamı 5 bitplane ($5000) ve composite renkli video sinyali (+$200) anlamına gelmekte. Bu register'daki diğer bitlerin anlamlarını, Doğan Türküler Hardware köşesinde diğer copper register'larıyla beraber açıklayacak. Biz şimdilik BPLCON0'ı bitplane adedimizi seçmek için kullanıyoruz. Örneğin 3 bitplane için buraya yazmamız gereken değer $3200 olmalıydı.

Bundan sonraki dört satır ile DIWSTRT ($008e), DIWSTOP ($0090), DDFSTRT ($0092) ve DDFSTOP ($0094) register'larına belli değerler yazıyoruz. Bu değerler yardımıyla ekran büyüklüğünü etkileyebiliriz. Örneğin DIWSTRT ve DIWSTOP ile oynayarak Overscan ekran yaratabiliriz. Bunu ilerde kullanacağımız için pek değinmiyorum. Yalnız verdiğim değerlerin normal bir 320*256 ekran yaratmak için kullanılan değerler olduğunu söylemeliyim.

$0108 ve $010a register'ları BPL1MOD (tek numaralı bitplane'ler için modulo) ve BPL2MOD (çift numaralı bitplane'ler için modulo) isimlerini taşımaktalar. Buraya yazacağımız değerler, bir sonraki satırın adresini bulmak için her ekran satırı sonunda ekran adresine eklenecek modulo değerlerini belirler. Verdiğim örnekte bitplane'ler hafızada alt alta yer aldığı için modulo değerleri 0 olmalıdır. Eğer bitplane'lerimiz özel bir amaç için yan yana dizilmişlerse, her iki modulo'yu da uygun değerlere ayarlamalıyız. İlerde blitter konusuna girdiğimizde hızdan kazanmak için bitplane'leri bu şekilde kullanacağız.

Copper listemizde bundan sonraki 10 satır ile bitplane adreslerini tanımlayabiliriz. $00e0 ve $00e2 (BPL1PTH ve BPL1PTL) ilk bitplane'in high ve low word'ünü taşır. Aynı şekilde diğer bitplane'ler tanımlandıktan sonra renkleri tanımlıyoruz. Bunun için renk register'larına istediğimiz renk değerini $0rgb olarak yazıyoruz, r, rengin kırmızı oranını, g ve b'de yeşil ve mavi oranlarını belirler. Renk register'ları $0180'den sonra gelen 32 word'dur (COLOR00-COLOR31). Verdiğim örnekte bütün renk register'larını sıfırladım. Programınızda resim ya da yazı kullanacağınız zaman, bunlara ait renkleri bu register'lara yazmalısınız.

Bundan sonra gelen satırlar sprite datalarının yerlerini tanımlamak için kullanılır. Fakat biz programımızda hiç sprite kullanmadığımızdan bunları da sıfırlıyoruz. Sprite kullanılacağı zaman, sprite'ın hafızada bulunduğu adresin üst ve alt word'ünü bu adreslere (SPRxPTH ve SPRxPTL) yazmalısınız. Sprite'lar hakkında şimdilik bir noktaya daha değineceğim. Mouse pointer'ı da bir sprite'dır. Sprite 0'ın adresini sıfırladığımız zaman sprite pointer'ı yok olacaktır. Bu yüzden programınızda mouse'u kapamak istiyorsanız sadece sprite 0 adreslerini 0 yapmanız yeter.

Şimdi dilerseniz programımızın kalan bir-iki ufak bilinmeyenini de açıklayalım. Programın Loop label'ından sonraki iki satırı, ekran tarama ışınının ekran sonuna gelip gelmediği kontrol edilir. Bunun için $dff006 register'ının içeriğine bakılır. Bu register'ın ismi VHPOSR'dir ve ekran tarama ışınının o anki konumunu gösterir. Eğer ekran tarama ışını 256. satıra (=$ff) geldiyse programımıza devam edilir. Aksi halde bekleme devam eder. Bu iki satırın amacı şu: Programlarımızda hareketli şeyler kullanmaya başlayınca bazen ekranda hareket eden kısımların titremeye başladıklarını görürsünüz. Bu, ekran tarama ışınının tüm hareketleri aynı anda gösteremeyeceğindendir. Bu durumda işlemlere başlamak için ekran tarama ışınının ekran sonuna varması beklenir. Bütün ekrandaki hareket işlemleri bu sayede ekran tarama ışını ekran dışında olduğu zamanlar yapılır. Ekran tarama ışınımız, ekranı 0. satırdan itibaren yeniden taramaya başladığı zaman da bütün değişen pikselleri update edecektir. Bu şekilde ekrandaki ufak tefek titremeleri de kaldırabiliriz. İlerde intro ve demo yazarken bu yöntemi umduğumuzdan da çok kullanacağız.

Mouse label'ından sonraki satırlarda $bfe001'in 6. bitini kontrol ediyoruz ve bu bit 0 ise programın çıkış rutinine geçiyoruz. Bu bit, mouse'un sol tuşunun konumunu gösterir. 6. bit 0 değerini taşıyorsa mouse'un sol tuşuna basıldı demektir. Mouse'un sol tuşuna basılmamış ise Loop label'ına geri dönülür. Devamlı tekrar edilmesini istediğimiz rutinleri bu yüzden Mouse label'ından hemen öncesine koymalıyız. Bu rutinler, mouse tuşuna basılana kadar tekrar edilir.

Hay allah, ne güzel tam öğrenmeye başlamışken yerimiz yine bitti. Programın başka açıklanacak yeri de kalmadı zaten. Gelecek ay, copper listesini kullanarak ufak bir rutin yazmaya ne dersiniz? Hem bu şekilde copper listesinin esas kullanılış şeklini de tam olarak görebilirsiniz. Hepinize bol byte'lı günler.

; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 
; >>>>GELISMIS ASSEMBLER - ÖRNEK PROGRAM <« 
; >>> 
TEMEL RUTİN 
.   <« 
; >>> 
by :Cem GENCER /1992 
<« 
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Q:
movem.l   a0-a6/d0-d7,-(a7)
bsr.s     Init
Loop:
cmp.b    #Sff,$dff006 
bne.s     Loop
« 
Mouse:
btst 
#6,$bfe001 
bne.s Loop 
beq.s Final
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 
; >» 
Turn alt-rutinler buradan sonra ... 
<« 
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Final:
lea      SysCop,a0 
move.l    (a0),50(a6) 
movem.l   (a7)+,a0-a6/d0-d7 
rts
Init:
move.l    4,a6 
lea      GfxName,a1 
jsr      -408(a6) 
move.l    d0,GfxBase 
move.l    GfxBase,a6
lea      SysCop,a0 
lea      Copper.a1 
move.l    50(a6),(a0) 
move.l    al,50(a6)
rts
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; >» Tüm datalar buradan sonra ... >> ; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

GtxName:
dc.b      'graphics.library',0,0 
SysCop:
dc.l     0 
GfxBase:
dc.l     0 
Copper:
CMOVE $5200,$0100 
CMOVE $3a81,$008e 
CMOVE $40cl,$0090 
CMOVE $0038,$0092 
CMOVE $00d0,$0094 
CMOVE $0000,$0108 
CMOVE $0000,$010a
CMOVE 
$0007,$00e0 
CMOVE 
$0000,$00e2 
CMOVE 
$0007,$00e4 
CMOVE 
$2800,$00e6 
CMOVE 
$0007,$00e8 
CMOVE 
$5000,$00ea 
CMOVE 
$0007,$00ec 
CMOVE 
$7800,$00ee 
CMOVE 
$0007,$00f0 
CMOVE 
$a000,$00f2
CMOVE 
$0000,$0180 
CMOVE 
$0000,$0182 
CMOVE 
$0000,$0184 
CMOVE 
$0000,$0186 
CMOVE 
$0000,$0188 
CMOVE 
$0000,$018a 
CMOVE 
$0000,$018c 
CMOVE 
$0000,$018e 
CMOVE 
$0000,$0190 
CMOVE 
$0000,$0192 
CMOVE 
$0000,$0194 
CMOVE 
$0000,$0196 
CMOVE 
$0000.$0198 
CMOVE 
$0000,$019a 
CMOVE 
$0000,$019c 
CMOVE 
$0000,$019e 
CMOVE 
$000a$01a0 
CMOVE 
$0000.$50la2 
CMOVE 
$0000,$01a4 
CMOVE 
$0000,$01a6 
CMOVE 
$0000,$01a8 
CMOVE 
$0000,$01aa 
CMOVE 
$0000,$01ac 
CMOVE 
$0000,$01ae 
CMOVE 
$0000,$01b0 
CMOVE 
$0000,$01b2 
CMOVE 
$0000,$01b4 
CMOVE 
$0000.$01b6 
CMOVE 
$0000,$01b8 
CMOVE 
$0000,$01ba 
CMOVE 
$0000,$01bc 
CMOVE 
$0000,$01be
CMOVE 
$0000,$0120 
CMOVE 
$0000,$0122 
CMOVE 
$0000,$0124 
CMOVE 
$0000,$0126 
CMOVE 
$0000,$0128 
CMOVE 
$0000,$012a 
CMOVE 
$0000,$012c 
CMOVE 
$0000,$012e 
CMOVE 
$0000,$0130
CMOVE 
$0000,$0132 
CMOVE 
$0000,$0134 
CMOVE 
$0000,$0136 
CMOVE 
$0000,$0138 
CMOVE 
$0000,$013a 
CMOVE 
$0000,$013c 
CMOVE 
$0000,$013e
CEND