Makine Dilinin Püf Noktaları

Makine

Dilinin

Püf Noktaları

Selam, makine dili uzmanı adayları. Demo veya intro yapabilmek için kullanılacak tekniklerin gizli kalmış yönlerini açıklamaya çalıştığımız yazı dizisi bu ay da devam ediyor. Bildiğiniz gibi, geçen sayıda takıldığınız herhangi bir nokta, öğrenmek istediğiniz herhangi bir teknik olursa, bana (Vedat Hallaç) yazmanızı ve takıldığınız rutini iyice açıklayarak, ne istediğinizi belirtmenizi rica etmiştim. Bu ay, İzmir'den Adnan ÖNCE-VARLIK adlı arkadaşınızın sorusuna cevap vereceğim. Unutmayın, yazıda ne kadar ilerlemiş olursak olalım, en basit konularda bile başa çıkamadığınız noktaları bana yazın. En kısa zamanda sorularınıza cevap vermeye çalışacağım. Arkadaşımız mektubunda, ekranın yarısının grafik, öteki yarısının karakter ekranı olmasını nasıl sağlayacağını sormuş. Biliyorsunuz bu efekt, adventure oyunlarında sık sık kullanılır. Ekranın üst yarısında bulunduğunuz sahnenin bir görüntüsü bulunur. Alt kısmında da sizin komutlarınızı girdiğiniz, ve bilgisayarın cevaplarını yazdığı karakter ekranı bulunur. Bu işlemi yapabilmek için, öncelikle raster interrupt'ların nasıl yapıldığını bilmeniz gerekir. Bu yazıda bu konuda kısaca bilgi vereceğim. Değişik türdeki interrupt'lar hakkında ayrıntılı bilgi almak için dergimizin 56. sayısını edinmeye çalışın. Şimdi raster interrupt'ını anlatmak için asıl soruna biraz ara vereceğim. Bu konudaki bilgisini yeterli görenlerin burayı okumasına gerek yok. Bilgisayarınız program çalıştırırken, bir interrupt sinyaliyle karşılaşırsa, işletimde bulunan ilk komutun bitmesini bekler, daha sonra sırasıyla A, X, Y register'larını, sıradaki komutun bulunduğu adresi ve status register'ını (flag'leri) Stack'e (yığına) atar ve $0314-$0315 adreslerinde alçak-yüksek bayt formatında (high-low byte. Mesela $0810 yazmak için $0314'e $10, $0315'e $08 değerleri verilir) bulunan adrese sıçrar. Diyelim ki programınız $8000'de ve $8008 adresindeki Lda $80FF komutunu işletiyor. O anda raster interrupt sinyali geldi (acele etmeyin. Raster sinyalinin ne olduğunu da anlatacağım) Lda $80FF komutu işini bitirir bitirmez, gerekli register'lar ve $800B adresini yığına atar. Daha sonra $0314-$0315 adresinde bulunan (diyelim ki) $00-$C0 değerleri alınır, ve bu değerlere bakılarak $C000 adresine sıçranır. Bu programda yazmak istediğiniz şeyleri yaptıktan sonra, (raster interrupt kullanıyorsanız) Inc $D019 komutuyla ortalığı düzenleyip, Jmp $EA81 komutuyla asıl programınıza ($800B)'ye geri dönebilirsiniz. Gelelim RASTER'in ne olduğuna... Bilgisayarınız, ekrandaki görüntüyü oluşturmak için televizyona bilgileri bir piksel (nokta) kalınlığında satırlar şeklinde gönderir. Bu tek nokta kalınlığındaki satırların her birine bir RASTER SATIRI adı verilir. Bu raster satırları, normal olarak televizyon ekranınızın en üstünün biraz daha üzerinden başlar ve en altının biraz daha aşağısına kadar devam eder. Bilgisayarınız, herhangi bir anda hangi satırın televizyona gönderilmekte olduğunu bilir, ve bu satırı size bildirebilir. Bu satırların her birinin bir numarası vardır ve bu sayılar $0000-$012F arasında değişir. En üstteki raster satırının değeri $0000, en alttakinin değeri de $012F'dir. Bu değerin son sekiz bitini $D012 adresinden okuyabilirsiniz. Eğer tüm işlemleriniz, yazı yazabileceğiniz ekranda yapılacaksa bu sekiz biti kullanmak size yetecektir. Fakat tüm ekran üzerinde değişik efektler yapmaya kalkarsanız, 9. biti de kullanmanız gerekir. İlk durumda sadece $00-$FF arasında kontrol sahibiyken, ikinci durumda $0000 - $01FF arasında adresleme yapabilirsiniz. Ekranda sadece $012F satır olduğundan bu değerden sonrasını da kullanmanıza gerek yoktur. Bu 9. biti $D011 adresinin son bitinde bulabilirsiniz. Yani dokuzuncu bitin değerini öğrenmek için Lda, And komutlarını kullanabilirsiniz. Eğer raster $00-$FF arasında ise yukarıdaki işlemin sonucunda sıfır bayrağı (zero flag) kalkacaktır. Eğer $0100-$012F arasında ise sıfır bayrağı inik kalacaktır. İyi de, raster satırının ne olduğunu bilmek ne işimize yarayacak? Bu soruyu bir örnekle cevaplayabiliriz; Ekranın üst yarısında arkaplan rengi siyah, alt yarısında ise beyaz olsun istiyorsak ne yaparız? Bu problemi çözmek için interrupt'ları hiç kurcalamayalım.

Program 1:
Sei
Beklel Lda $DO12
Cmp #$A0
Bne Bekle
Lda $DOl11
And #$80
Bne Bekle
Lda #$01
Sta $DO20
Lda
Bpl Bekle2
Lda $DOl11
Bmı Bekle3
-Lda #$00
Sta $DO20
Jmp Beklel

Yalnızca basit karşılaştırmalar kullanarak bu problemi halledebiliriz. Burada yapılan işlem basittir: Önce işimizi engellemesin diye tüm interrupt'ları kapatıyoruz (bir de Sei'yi kaldırıp programı çalıştırın ve tuşlara basmayı deneyin), ve raster'in $00A0 satırına gelmesini bekliyoruz. Buraya gelinir gelinmez çerçeve (arkaplan) rengini beyaza çeviriyoruz ve 9. bitin önce bir, sonra da sıfır değerini almasını bekliyoruz. Burada kullanılan metodu öğrenirseniz, her seferinde And $80 komutu verip sonra sıfır bayrağına bakmanıza gerek kalmaz. Eğer bir baytın 8. biti 1 ise Bmi komutu sıçrama yapar, 0 ise Bpl komutu. Bu işlemi yapınca, raster'i tam $0000 satırında tekrar yakalıyoruz (ki burası görünen ekranınızın üstündedir) ve çerçeve rengini siyaha çeviriyoruz ve aynı işi tekrarlamak üzere rutinin başına sıçrıyoruz. Aslında asıl sorunu burada çözmüş bulunuyoruz. Yani istenen koordinata gelene kadar bekleyip karakter ekranına geçeriz (Lda And #$DF Sta $D011 veya Lda #$1B Sta $D011). Sonra ekranın tepelerinde bir yerde tekrar grafik ekranına gireriz (Lda $D011 Ora #$30 Sta $D011 veya Lda #$3B Sta $D011). Gördüğünüz gibi ekranın herhangi bir özelliğini istediğimiz anda değiştirebiliriz. Bu iş için sadece raster'ın gereken yere gelmesini beklememiz, sonra da değişiklikleri yapmamız yeterlidir. Bu aşamada değişik efektler yaratmayı, ekranı üçe, dörde, onbeşe, vb. bölmeyi denemenizi öneririm. Demin anlattığım işlemi yapması oldukça kolaydır, fakat bekleme sırasında başka işler yapabilecekken, yalnızca iki komutu işlettiğiniz için verimi düşüktür. Oysa asıl anlatacağımı bilirseniz, bilgisayarınız, istediğiniz raster satırına geldiğinde ana işini bırakıp, sizin işlemlerinizi yapabilir. Yani interrupt'ları belli raster satırlarına geldiği zaman yaratabilirsiniz. Bir raster interrupt'ı yaratmak için şöyle bir program kullanabilirsiniz:

Program 2:
Sei
Lda #$00
Sta $DCOE
Lda #$7F
Sta $DCOD
Lda #$01
Sta $DOLA
Lda #$Raster
Sta $DO12
Lda $D011
Ora #$8 (And #$7F)
Sta
Lda #Adres
Sta $0314
Lda #Adres
Sta $0315
Cli
Döngü Jmp Döngü

Yukarıdaki program parçacığını kullanarak, Raster adlı satıra gelince Adres adlı adrese sıçranmasını sağlayabilirsiniz. Şimdi de yazdığımız onca komutun ne işe yaradığını anlatayım: $DC0D-$DC0E adreslerinin değerlerini, zamanlama interrupt'larını engelleyecek şekilde ayarlıyoruz (Sayı 56'ya bakarak bu konuda ayrıntılı bilgi alabilirsiniz). $D01A'ya verdiğimiz $01 değeri ise sadece raster interrupt'ı istediğimizi söylüyor bilgisayara. Daha sonra istediğimiz raster satırının değerini (örnekte Raster) $D012 adresine yazıyoruz. Mesela interrupt'ın $0A0 satırında yapılmasını istiyorsak, örnekteki Raster yerine $A0 yazmamız gerekir. $D011 adresinin son bitini 1 veya sıfır yaparak da 9. bitin değerini ayarlıyoruz. Ora #$80 komutunu kullanırsak son bit 1, And #$7F kullanırsak son bit sıfır olur ('8. bitin değerini sıfırla, geri kalanlarını olduğu gibi kullan' anlamına gelir bu komut). $0A0 satırı için burada And #$7F kullanmamız gerekir. Daha sonra da $0314-$0315'e Adres değerini alçak-yüksek bayt formatında yazıyoruz (<Adres: Adres'in alçak baytı, >Adres: Adres'in yüksek baytı, Adres=$C080 ise <Adres=$80, >Adres=$C0 olur). Cli komutuyla interrupt'ları açtığımız andan itibaren, her $00A0 raster satırına gelindiğinde yapılan iş (JMP Döngü) bırakılır, ve $C080 adresine sıçranır.

Kİ Bir

Tabi ki bir de interrupt program yazmalıyız ki, bilgisayarımız kilitlenmesin. Mesela bilgisayarınız her adresine geldiğinde ekranı karakter ekranına geçiren ve aynı zamanda arkaplan (çerçeve) rengini ve önplan (ekran) rengini beyaz yapacak bir interrupt programı yazalım:

Program 3:
Lda $DO11
And #$DF
Sta $DOl1
Lda #$01
Sta $DO20
Sta $DO21
Inc $DO19
Jmp $EASI

Gördüğünüz gibi, yapmamız gereken tek şey, karakter ekranına geçmek, ve $D020-$D021 renklerini beyaz yapmak. Ama unutmamanız gereken şey, $D019'un değerini bir arttırmak. Eğer bu işlemi yapmazsanız, interrupt'tan çıkar çıkmaz, yeniden interrupt'a geri dönersiniz. Kısaca programınız düzgün çalışmaz. Arkadaşımızın sorununu çözmek için, bir de ekranın üstünü grafik yapmamız yeterli olacaktır. Bu iş için de “Jmp Döngü' komutunun yerine şu komutları yazabiliriz:

Program 4:
-Döngül Lda $DO11
Bpl Döngül
Döngü2 Lda $DO11
Bmı Döngü2
Lda
Ora #$30
Sta $D011
Lda #$00
Sta $D020
Sta $D021
Beq Döngül

Yani, bir yandan ekranın en tepesine gelinmesini beklerken, diğer yandan ekranın ortasına gelinince ekran karakteristiklerini değiştiren iki programın ortak çalışması sonucu ekranı iki bölüme ayırabilmiş oluyoruz. Yukarıdaki örneğin en sonuna dikkatinizi çekmek istiyorum. A'ya doğrudan sıfır verdiğimiz için sıfır bayrağı bu kısımda mutlaka kalkık olacaktır. Yani JMP komutu yerine Beq komutunu kullanırsak, hem daha hızlı, hem de daha kısa program yazmış oluruz. Tabi ki tek başına pek bir fark yaratmaz, ama tek bir cycle'ın bile değerli olduğu rutinler yazmaya kalktığınızda bu tür bilgiler işinize yarayacaktır. Bu aylık da bu kadar. Yazıyla ilgili programları her zamanki gibi

Döküm eki'nde bulabilirsiniz.

Mektuplarınızı bekliyorum. Gelecek aya kadar hoşçakalın.