Atölye

Her ay Atölye'ye konu bulmak daha zor oluyor. Ne olur biraz yardım edin. Yaptığınız programları ve açıklamalarını, ya da yapamadığınız programların fikirlerini memnuniyetle kabul ederim. Eğer bu da işe yaramazsa her ay bu sayıda olduğu gibi komik komik programlarla idare etmek zorunda kalırsınız. Uyarması benden. Yukarıdaki kötümser uyarıya pek kulak asmayın. Bu ayki program o kadar da kötü değil. BASIC kullanıcılarının çerçevenin üst kısmına ait alt kısmına 24'er karakterlik mesajlar yazmalarını sağlayan bir rutin tanıtacağım bu ay. Bu mesajlar normal karakter setinde olacaklar ve istediğiniz renkte görünebilecekler. Ama sistemi biraz zorladığımız için diskten yükleme yapılırken bilgisayarınızı kilitliyor ve BASIC'i oldukça yavaşlatıyor. Bunun yanında iyi yanları da var programın, Mesela üst ve altta 8'er sprite kullanılmasına rağmen ekran sınırları içinde kullanılan SPRITE'ları hiç etkilemiyor. Yani toplam 24 sprite'ı bir anda ekranda tutuyor. Tabii ki sprite'ları gerekli şekilde MULTIPLEX etmiyor. Yani SPRITE'ınızı BORDER sınırlarının altına ya da üstüne çıkarmaya çalışırsanız ortalığı karıştırırsınız. Bu yazıda ilk olarak BASIC'cilerin programı nasıl kullanabileceklerini anlatacağım. Eğer yeterince yerim kalırsa bir de makine dili kullanıcıları için rutinleri açıklamak niyetindeyim. Eğer bu sayıda yerim kalmazsa bile gelecek sayıda mutlaka rutinleri açıklayacağım (çok değerli oldukları için değil, makine dili meraklılarını üzmemek için). Programın yapabildikleri o kadar fazla değil. İsterseniz SYS ile çağırabileceğiniz adreslerin ve yaptıkları işlerin listesini vereyim önce: $C000 — 49152: Border'ları açan ve sprite'ları...

Atölye

Vedat Hallaç, interrupt'larla başa çıkan interrupt'ları çalıştırır. Bu arada görüntüde arızalar yaratacak olan $3FFF ve $FFFF adreslerini temizler. $C180 - 49536: Yazı alanında yer alan 24 karakteri üst çerçevede yer alan bölgeye yerleştirir. $C18C - 49548: Yazı alanında yer alan 24 karakteri alt çerçevede yer alan bölgeye yerleştirir. $C100 - 49408: Sprite'ların grafik datasını temizler. Yazıları silmek istediğinizde ya da programı ilk yüklediğinizde kullanmalısınız. $C200 - 49664: Interrupt'ları kapatarak kontrolü ROM'lara devreder. Hıza ihtiyacınız olduğu zamanlarda, ya da yükleme yapmadan hemen önce bu adrese sıçramalısınız. Demin de söylediğim gibi, interrupt'lar açıkken diskten yükleme yapmaya kalkarsanız bilgisayar kilitleniyor. Interrupt'ları geri açmak için $C000'a sıçradığınızda yazılar hiç değişmeden geri dönecektir. Bir de POKE'larla erişebileceğiniz adreslerin kısa bir listesini vereyim isterseniz: $C1B0 - 49632: Üstteki yazının hangi renkte yazılacağını belirler. $C1B1 - 49633: Alttaki yazının hangi renkte yazılacağını belirler. $C1B8 - 49592: Yazı alanının başlangıcı. Bu alan 24 bayttan oluşur ve yazılacak yazının ekran kodlarını tutar. Yani “A” harfini yazdırmak için ASCII kodu olan $41 (65)'i değil $01 (1)'i kullanmalısınız. Programın tam olarak nasıl kullanılacağını belirtemem. Bunun için en iyi yöntem kullana kullana bu işi sizin öğrenmeniz olacaktır. Burada size sadece benim aklıma gelen incelikleri belirteceğim. Kısa bir liste halinde vereceğim bu püf noktalarına çok güvenmeyin. Hatta kendi püf noktalarınızı oluşturmaya çalışın. İşte benim fark edebildiklerim:

Rutinin Bellek Haritası 1. SYS ile Çağrılan Adresler:

der, yazıları siler. Sprite'lara yazar. Sprite'lara yazar.

BASIC'e bırakır.

belirler.

belirler.

Diğer adıyla: Yazı alanı.

$C000-49152: Boörder'ı açacak interrupt rutinini aktive e- $C100—49408: Sprite grafik alanını (dolayısıyla borderdaki $C180-—49536: Yazı alanındaki karakterleri üst borderdaki $C18C-49548: Yazı alanındaki karakterleri alt borderdaki

$C200—49664: Interrupt'ı (ve border'ı) kapatır, kontrolü

2. POKE ile Kontrol Edilen Adresler: Üst borderda yer alan yazıların rengini

$C1EB1-49633: Alt borderda yer alan yazıların rengini

$C1B8-$C1CF - 49592-49615: $C180 veya $C18C ile çağrılarak, sprite'lara yerleştirilecek yazının yazılacağı yer. Vereceğim önemli noktalar: 1) Programınızın en başında SYS 49408 komutunu verin ve sprite alanlarını temizleyin. Sprite alanı olarak $E000 civarı kullanıldığı için BASIC programlarınıza bu şekilde zarar veremezsiniz. 2) Eğer uzun süre aynı yazı ekranda duracaksa bu yazıyı sprite'lara interrupt'lar kapalıyken yazdırın. Bu sayede işlem çok daha kısa sürecektir. 3) Yazıları ekrana yazdırmak için örnek programdaki metodu kullanmayın. Bunun yerine gerekli sayıda DATA satırlarına yerleştirin ya da doğrudan belleğe POKE edin. Bu sayede işiniz daha hızlı görülür. 4) Yazı alanına hiçbir zaman 24 karakterden az değer yazmayın. Daha önceden yazılmış olan karakterlerin artıkları sizin yazılarınızı bozabilir. 5) Altta ve üstte aynı mesajı yazmak istiyorsanız SYS 49536 ve SYS 49548 komutlarını ardışık olarak verin. 6) Yazı yazmadan önce interrupt'ı kapatın (SYS 49664). Her şey hazır olduktan sonra interrupt'ı tekrar açabilirsiniz (SYS 49152). 7) Eğer karmaşık hesaplara girişecekseniz, interrupt'ı kapatın. Çünkü interrupt'lar açık olduğu zaman bütün hesaplar yüzde otuz ile elli arasında yavaşlıyor. 8) Programlarınız sprite kullanıyorsa hiçbir şey değiştirmeye çalışmayın. Sadece sprite'ların görülebilir ekran sınırları içinde kalmasına dikkat edin. Eğer siz sprite'ınızı benimkilerin yanına getirirseniz hiç de hoş olmayan görüntülerle karşılaşırsınız. 9) $3FFF (16383) ve $FFFF (65535) adreslerini elinizden geldiğince koruyun. Bu bölgelere bir değer yazarsanız border'da garip siyah çizgilerle karşılaşırsınız. Aslında isterseniz çerçevede yana kayan çizgiler yaratabilirsiniz. Şu programı bir deneyin isterseniz:

10 FOR R-0 TO 7:POKE 65535,2.R:
NEXT:GOTO 10

Yukarıdaki program $FFFF adresinde yer alan baytın bitlerini sırasıyla yakarak sola kayan ince şeritler oluşturur. Program, sizin de sprite kullanmanıza izin verebiliyor. İsterseniz şu satırları girin bir:

POKE 53248,100:POKE 53249,100
POKE 53269,1:POKE 2040,0

Nasıl, 17. sprite'ınız da garip garip sırıtıyor ortalıkta, değil mi?

Aslında programın kullanımıyla ilgili söyleyebileceğim başka bir şey kalmadı. MDE ve BDE yardımıyla BORDER ve BORDER.DEMO programlarını yazın ve çalıştırın. BORDER.DEMO yardımıyla BASIC'ten bu programa neler yaptırabileceğinizi öğrenebilirsiniz. Canınız sıkıldığı zaman programı RUN/STOP tuşuyla durdurun ve SYS 49664 komutunu girerek devreden çıkartın. 500. satır numarasından başlayan alt program, A$ gibi bir değişkenin içeriğini yazı alanına nasıl yerleştireceğinizi gösteren bir örnektir. Kendi programlarınızda burayı olduğu gibi kullanabilirsiniz. Yalnız dikkat, program sadece harfler, sayılar ve basit işaretlerle başa çıkabilir. Eğer DATA satırları yardımıyla harf yazdırmak niyetindeyseniz mesajı ekranın sol üst köşesinden başlayacak şekilde yazın ve $0400-$0418 (1024-1048) arası bellek alanının içeriklerini bir yere not edin. Bu sayıları programınızda olduğu gibi kullanabilirsiniz. Eğer kaset kullanıcısıysanız, 10. satırda yer alan LOAD komutunu tamamen silin ve makine dili programını kendiniz yükleyin. Makine dili kısım belleğe yüklendikten sonra BASIC program LOAD komutu olmadan da çalışır.

Sıra Makine Dili Açıklamalarda

Program, tüm makine dili programları gibi $C000'dan başlıyor. İntrolar yazı dizisini izleyen herkes bilir; interrupt kullanan bir program yaratmanın ilk adımı interrupt vektörlerini, raster interrupt'ının başlangıç satırını ve CIA interrupt'larını gerekli sayılarla ayarlayıp, VIC'e Raster interrupt yapmasını söylemektir. Bu işi yapmak için $C000-$C02B arasında yer alan rutini kullanıyoruz. İlk olarak BORDER programını yazın, daha sonra bir monitör programıyla size söylediğim adresleri disassemble edin. Sonra yazıyı okurken bu programı izleyin. Karışık gibi duruyor, ama emin olun bu sayede programı daha iyi anlayacaksınız. İlk olarak $C000 adresinde, CIA'i ayarlıyoruz ($DC0E). $C006 adresinde yer alan dört komut yardımıyla $0314-$0315 adreslerini $C030'u gösterecek şekilde ayarlıyoruz. Bu sayede interrupt rutininin $C030'da yer aldığını bilgisayara bildiriyoruz. Bundan sonra yer alan iki komut, elektron $F9 (249.) satıra geldiği zaman $C030'a sıçranmasını sağlayacak raster interrupt'ı da gerekli şekilde ayarladıktan sonra (bak. MAKİNE DİLİNİN PÜF NOKTALARI, Konu: RASTER INTERRUPT) standart işimiz bitiyor. Artık tek yapmamız gereken şey, border açıldığında şeritler halinde kötü görüntüye yol açabilecek $3FFF ve $FFFF adreslerini sıfırlamak, interrupt'a izin vermek ve BASIC'e geri dönmek. Artık yüzde otuz yavaşlamış, fakat alt ve üst ekran açık bir bilgisayarınız var. Kolay gelsin. Tabii ki sizi bu kadar kolay atlatamam. Artık kurtuluş yok. Asıl rutini ayrıntılarıyla anlatmak zorundayım. Neyse ki kolay bir rutin. Geldik $C030'a. En iyisi rutin kendi kendini anlatsın size: “Burası Raster Satırı $F9. Yani ekranın kapandığı yer. İlk olarak Commodore'u dolandırıp ekranın alt ve üstünü açmalıyım. Yani görünebilen ekranı 24 satır olarak tanımlayacağım. Ama önce VIC'e interrupt yapıldığını bildireyim: INC $D019. Şimdi vereceğiz ve Commodore border'ları açacak. “Programcının ekranda sekiz sprite'ı da kullanabilmesini istiyorum. Bu yüzden sprite datalarını değiştirmeden önce eski dataları bir yerlere koyayım. Bu sayede ekran görüntüsü başlamadan hemen önce bu değerleri geri yazabileceğim. Programcının sprite'ları da yukarıda ve aşağıda 16 sprite gösterilmemiş gibi görünmeye devam edebilecekler. İlk olarak $D015'in değerini (programcının açık olan sprite'larını) $C1EE'ye kovalıyorum. Abzürd sprite'lar görünmesin diye $D015'e de 0 koyuyorum (meali: Sprite'lar kapalı!). Renkleri de kurtarmalıyım, yani $D027-$D02E gider $C1E4'e. Sonra da koordinatlar saklanmalı: $D000-$D010, $C1FF'e kopyalanmalı. “Sprite'ları kurtardık, şimdi de yeni sprite datalarını ayarlayalım: Bütün Y koordinatlarını 1 yapalım ilk olarak. Bu sayede $0101 (257.) raster satırında sekiz tane sprite olacağını bilgisayara söylüyorum. Bitişik sekiz sprite'ın da ekranın ortasında yer almasını sağlayacak X koordinatlarını da $D002, vb. adreslerine yazdıktan sonra son sprite'ın MSB'sini 1 yapıyorum (Ne yapalım, x koordinatı $0100'e denk geliyor. Ben de $D010'a yazdım). Sprite'lar $E000'ın altında duruyor. Bu durumda yapılacak tek şey $DD00'a yazmaktır. Ben de öyle yapıyorum. “Renkleri de unutmamalıyız. Alt tarafın rengini alıyorum ve $D027-$D02E'ye bu rengi yazıyorum. Bir de sprite'ların grafik datalarının $E000'dan başlamaları gerekiyor. N'apalım, ben de $C7F8'i 8580 yapıyorum. $C08B'ye bakınca bu değer gibi duruyor, ama dikkatli bakınca. Y sıfır olduğunda bu değerin de olduğunu hemen fark edebilirsiniz. Bunun sebebini iki soruya cevap vererek açıklamalıyım: *1) Niçin $C7F8? Çünkü, sprite'ların grafik dataları aktif olan bank'in karakter ekranı sonunda yer alır. $DD00'a 0 yazınca $C000-$FFFF arası aktif bank oldu. Bu bank'in karakter ekranı da $0400 bayt ileriden başlar ($C400). Bu ekranın sonundaki sprite alanı da bank'in başından $07F8 baytı ileriden başlar. Bu da bizim $C7F8'e denk.

geliyor. Diğer sprite'ların datalarını da sırasıyla $C7F9, $C7FA, vb.'ne yazacağım: “2) Niçin? İlk olarak grafik datalarının bank başından ne kadar ileride olduğuna bakarız: $B000-$C000 = $2000. Bunun 64'de birine bakalım ne çıkacak: $2000/$40 = $80! Ne ilginç. Bizim $80 buradan geliyormuş demek! “Hadi bakalım yola devam edelim. Şimdiye kadar neleri ayarladık? X, Y koordinatları tamam. Renkler tamam. Grafik datalarının yeri tamam. Evet, sprite'ları bitirdik. Bir de gösterdik miydi bitecek işimiz. Hadi yazalım $D015'e. Şimdi elektron ekranın üstüne çıkana kadar sabırlı sabırlı beklemeliyim. $D011'de bir yerlerde elektronun nerede olduğunu da öğrenebilirsin demişlerdi bana. Son biti miymiş, neymiş? En iyisi son bit temizlenene kadar bekleyeyim de göreyim. (BMI, son bit 1 olduğu sürece dallanır). Ne güzel, ekranın tepesine vardım. Şimdi yeni Y koordinatlarını gireyim bakalım: Y'ler 10 olsun! “Renkleri $C1E0'dan alıp yerine yazdıktan sonra bir tek işim kalıyor: Grafik datalarını $E200'dan alınacak şekilde ayarlamak. Sprite'lar gerekli yerde görünürler artık. “Son işim ekranın başından biraz önceye kadar beklemek artık. Ekrana girmeden hemen önce eski sprite verilerini de yerleştiririm, bank'i düzeltirim ve $EA31'e sıçrayarak kontrolü Commodore'a geri veririm. “Ben bu işi saniyede 20 kere yapıyorum. Ağır iş yaptığını söyleyenlere duyurulur. Bu arada normal BASIC zamanının yüzde 30-yüzde 50 arası bir miktarını çalıyorum, ama o bunu kaldırabilir. Bir tek KERNAL beni çekemiyor. Program yüklemeye kalktığında beni görürse intihar ediyor. Tabii ki beni de birlikte götürüyor. Lütfen bu fırsatı ona vermeyin. $C200'ı kullanarak beni bir süre için kapatabilirsiniz. $C000'la yükleme sonrası geri açarsanız sevinirim. Beni kullandığınız için teşekkürler. Artık sözü babama bırakıyorum.” Sağ ol, programcık. Geri kalan birkaç rutini açıklamam gerekiyordu benim de. İlk olarak $C100'da yer alan basit bellek doldurma rutinini anlatayım. $FB-$FC'yi $E000'ı gösterecek şekilde ayarlıyorum, bu adresi indeksli şekilde 255 kere temizletiyorum. Böylece $E000-$E0FF arasını sıfırlamış oluyoruz. Şimdi $FC'yi bir artırmalı ve değeri #$E4 olana kadar temizleme işlemine devam etmeliyiz. Bu sayede $E000-$E3FF arasını temizlemiş oluruz. Bu rutincik de böylece aradan çıkar. Programın can alıcı rutinlerinden birine geldi sıra. Yani bir karakter dizisinin içinde yazan yazıyı grafik datası olarak sprite'lara yerleştirme rutini. Bu rutin karakter ROM'una erişirken ortalığı karıştırdığı için başlamadan hemen önce kullanıyor. Bu yüzden border açıkken kullanılırsa bir-iki ekran taraması süresince ortalığı karıştırabiliyor. Hemen sonra $01'e yazarak $D000'da karakter ROM'unu bulabilmeyi garantiliyoruz. Bundan sonra yaptığımız işlemler biraz karışık gelebilir size (en azından bana öyle geliyor). Burada karşılaşacağımız en büyük problem, sprite'ların grafik datalarının garip dizilişi. Rutinde uzunluk ve hız dengesini kurmak için çok uğraştım. Eğer her şeyi tablolara yerleştirmeye kalksaydım, bu rutinin en az 5-7 katı hızlı bir rutin ortaya çıkabilirdi, ama rutin de $C600 sınırlarına dayanırdı herhalde. Bu yüzden sadece n'inci (n = 0..23) karakterin grafik datasının ilk baytını hangi adrese yerleştireceğimi tutan bir tablo yaptım. Bu tablo 24 bayttan oluşuyor (oldukça kısa yani). Bunun yanında, sırtımızdan da ağır bir yükü kaldırıyor. Bu rutini alta ya da üste yazı yazarken kullanmayı düşünüyoruz. Bu yüzden belli adresler ya $E000 ve $E100 (alt yazı) ya da $E200 ve $E300 (üst yazı) değeriyle başlıyor işe. Bu değerleri $C180 ve $C18C'deki rutinler ayarlıyor. Sizin şu anda bakmakta olduğunuz program üst tarafı değiştirmek için ayarlanmış olan $E2 ve $E3 değerlerini içeriyor. Şimdi rutini yavaşça ve dikkatlice inceleyelim:

1. X (harf sayacı) sıfırlanır. 2. $FB-$FC bileşik değişkeninin (terimi uydurdum, korkmayın. Sadece birlikte bellekteki bir adresi gösteren değişken çifti demek istiyorum) yüksek değerlikli baytını $E2 yapıyoruz. 3. A, yani sayaç 12'ye eşitse ya da 12'den büyükse bu değeri 13 yapıyoruz. Çünkü bu 12'den sonra grafik datası bir sonraki bloğa ($E0XX'se $E1XX'e, $E2XX'se $E3XX'e) taşıyor. 4. Şimdi de düşük değerlikli baytı okuyalım. Harfin grafik datasının nereden başlayacağını belirten tablodan baytı alıyoruz (LDA $C1A0,X) ve $FB'ye yazıyoruz. Grafik baytları işte bu adresten başlayarak yazılacaklar. 5. Harfe ait grafik datası nerede? Kolayca hesaplayabiliriz bunu. Sadece harfin ekran kodunu sekizle çarpıp $D000'a eklememiz gerekli. Bir sayıyı sekizle çarpmak için üç kere ASL kullanmalıyız. Ama değer iki bayta taşabileceği için (129 x 8'e bir bakın). $FE'yi temizleyip, yüksek değerlikli baytı buraya kaydırmalıyız:

LDA $CIB8,X
ASL
ROL SFE
ASL
ROL SFE
ASL
ROL SFE
STA SFD

Bu rutin A'yı sekizle çarpıp, $FD-$FE bileşik değişkenine yazar. Sadece önceden $FE'yi temizlemiş olmalısınız. Daha sonra $FE'ye ekleyeceğimiz karakterin grafik datasının adresini bildirecektir.

6. Y'yi sıfırladıktan sonra, ($FE), Y'yi:

(SFB), Y'ye taşırız. Yani, karakterin ilk baytını sprite'a yerleştiririz. Ama ne yazık ki Y'yi artıramayız şimdi. Çünkü sprite datasında bir alttaki bayt, şu andaki değerin üç fazlasında yer alıyor. Yani ($FE-$EC'ye bir eklemeli, ($FB-$FC)'ye üç eklemeliyiz. Buradaki rutinde bana ait bir keklikle karşılaşıyorsunuz. $C160'a bakın. Tek bir sprite'a ait grafik datasının hiçbir baytı, diğerlerinden farklı bir sayfada yer alamaz. Çünkü bu datalar $XX00, $XX40, $XX80 ve $XXCO adreslerinde yer alabilir sadece. Hiçbir zaman başlayan bir sprite'a ait data $E100'a taşamaz. Bu yüzden $C160- $C163 arasında yer alan dört bayt, gereksiz yere işletiliyor. 7. Şimdi büyük bir problemle karşı karşıyayız. Sayaç olarak kullanabileceğimiz registerimiz kalmadı çünkü. Oysa bize sekize kadar sayabilecek bir değişken lazımdı. Biz de, sekize tam bölünebilen $FD-$FE adreslerinin düşük değerlikli baytının ($ED) ilk üç bi- 'tine bakarız. Başlangıçta bu üç bit sıfır olan (sekizle çarpılan bir sayı ne olursa olsun ilk üç biti sıfır kalır). Sekiz arttıktan sonra bu baytın ilk üç biti gene sıfır olacaktır. Bu ufak noktayı yakaladığımıza göre hemen yararlanalım: $FB'yi alırız, #$07 ile AND'leriz. Eğer sonuç sıfırsa karaktere ait sekiz grafik baytını da transfer ettiğimizi anlarız ve döngüyü terk ederiz. Geçmiş olur böylece. En zor kısımlardan birini oldukça kestirme bir şekilde atlattık çünkü. 8. Rutini bitirdik. Sadece sayacı, yani X'i bir artırıp, $18'e yani 24'e gelip gelmediği-

- ne bakmamız gerekiyor şimdi “Bunu çocukken de yapardık biz!” deyip bu ayrıntıyı da aradan çıkarttıktan sonra... 9. $01'e yazdım ve ROM'lar geri geldi. CLI dediğimde de interrupt kaldığı yerden işine devam etti. RTS dediğinde de BA-SIC'e döndüm. Geriye anlatılması gereken üç kısa rutin kaldı. $C180'deki, $C128'e $E2, $C130'a $E3 yazıyor ve $C120'ye atlıyor. Yazı alanını üst spritelara taşıyor yani. $C18C'deki de $C128'e $E0, $C130'a da $Eİ yazarak bu alanı alt spritelara yazdırıyor ($C120'ye sıçrayarak tabii ki). $C200'da yer alan küçük rutin de, $0314-$0315'i düzeltiyor, VIC'e “Artık interrupt yapma!” emrini veriyor ($DO19- $DOLA- A) ve CIAI'e “Sen de zamanlayıcını çalıştır artık” diyor ($DCOE- 1). Sonra da BASIC'e dönüyor. Eski hızma kavuşmuş, ama border'ı kapalı olana tabii ki. Eh, hâlâ bu yazıyı okuyorsanız, siz gerçekten bu işin ustası olmuşsunuz demektir. En iyisi siz bizi okumaya devam edin. Su Şişesi'nde yazanlara çok güvenmeyin, çünkü Can hep kopya çekiyor cevap verirken(!).