YAZILIM Atölye
Atölyemize hoş geldiniz. Üç aydır devam etmekte olan köşemizde oldukça yetersiz olan BASIC'imizi çok daha kullanışlı hale getirebilecek programlar yazıp, tanıtıyoruz. Asıl amacımız, makine dili bilmeyen arkadaşlarımızın da makine dilinin rahatlığından faydalanmasını sağlamak. Tabii bu arada işinize yarayacak yardımcı programlar da yaratabilirsek ne mutlu bize. Bu programları sadece BASIC kullanıcıları için hazırlamıyoruz ama. Programların nasıl mantıklar üzerine kurulduğunu anlatırken, makine diline yeni başlamış arkadaşlara da yardımcı olabildiğimizi umuyoruz. Bu sayımızda grafik severler için bir programımız var. 30K'lık BASIC alanına dokunmadan da grafik ekranların kullanılabileceğini ispatlayan bir program bu. Program sadece beş komuttan oluşuyor. Ama ROM rutinlerini oldukça fazla kullandığı için biraz yavaş işliyor. Bu yavaşlığı ortadan kaldırmak tabii ki mümkün, ama programın işleyişini anlatırken bu konuya değinmek daha iyi olur. Biliyorsunuz C-64 aslında 64K RAM'e sahip. Ama tüm bu bellekten yararlanabilmek için oldukça iyi derecede makine dili bilgisine sahip olmanız gerekli. BASIC kullanıcıları için ise gizli bölgelere ulaşmak imkansız. Ancak makine dilinde yazılmış programcıklar yardımıyla bu alanlara bilgi saklayabilirsiniz. Bu ay anlatacağım grafik paketçiği de bu kullanılmayan alanlara BASIC kullanarak erişebilmenizi sağlıyor. Bilgisayarınızın grafik işlerini düzenleyen çipi VIC, RAM'in üzerinde duran ve aslında bomboş duran bu alanı kullanmanızı engelleyen ROM'ları hiçbir zaman dikkate al-
maz. Eğer bir şekilde bu RAM'in altına grafik datalarınızı yazabilirseniz ve VIC'in bu alanı göstermesini sağlayabilirseniz, grafik dataları sizin BASIC alanınıza ihtiyaç duymaz. Sadece grafiğin kullandığı alan olarak
Vedat Hallaç düşünürsek, bu işlem size yaklaşık 8K'lık bir kazanç sağlar. Oysa asıl bellek kazancınız bu kadarcık değildir. BASIC'de grafik kullanmaya kalkarsanız, büyük bir ihtimalle $2000-$4000 arasını tercih edersiniz. Böyle bir seçim ise BASIC alanını 6K ile sınırlamak anlamına gelir. Programın açıklamasına girişmeden önce grafik kullanımı ve 64K RAM kullanırken nelere dikkat etmeniz gerektiği konusunda ufak bir özet çıkarmayı düşünüyorum. Grafik konusunda detaylı bilgiyi dergimizin eski sayılarında ele almıştık. Eğer buradaki bilgiyi yetersiz görürseniz eski sayılarımızı inceleyin. İlk olarak “VIC registeri” derken neden bahsettiğimi anlatmalıyım. C-64 türü bilgisayarlarda (Motorola CPU kullananlar) giriş/çıkış işlemleri için belleğin bir bölümü ayrılmıştır. Her özel çip (VIC, SID, vb.) bellekte kendine ait bir alan ayırır. Bu çipin registerleri de bu alanda bulunan ve çiple sizin aranızda bir iletişim hattı kuran adreslere verilen addır. VIC çipi $D000 - 53248 ile $D3FF - 54271 arasını kendisine ayırmıştır. Ama fazla bir iletişime ihtiyacı olmadığı için yalnızca $D000 ile $D02E arasını kullanır. Diğer adreslerde ise bu bölgenin kopyaları bulunur. Bu kopyalardan herhangi birine yapılan okuma-yazma işlemleri doğrudan doğruya $D000-$D02E arasında belirlenmiş adreslerle yapılır. Yani $D000 ile $D000 adresleri arasında herhangi bir fark yoktur. Grafik ekranı açmak, yerini değiştirmek ve çok renkli moda geçmek için üç adet VIC registeri ve isimleri şöyledir: $D011 VIC kontrol registeri 1, $D016 VIC kontrol registeri 2, $D018 VIC bellek kontrol registeri. Bu kontrol registerlerinin her biti özel bir işlemi kontrol eder. VIC kontrol registeri 1'in bitleri şu işleri yapmakla yükümlüdür: 7 Raster'in 9. biti, 6 Extended (genişletilmiş) renk modu, 5 Bit-map modu (grafik modu), 4 Ekran açık/kapalı, 0=kapalı, 3 24/25 satır gösterimi, 2-0 Ekranın aşağı kayma miktarı. 0-7 piksellik yumuşak kaymalar bu adresle yapıla- Bu bitleri adrese yazmak için, 2^(bit no)
formülünü kullanarak belleğe yazılacak değeri elde etmelisiniz. Bu karışık işlemler arasında bizi ilgilendiren (neyse ki) yalnızca 5. bit. Bu biti 1 yaparak ekranı karakter modundan grafik moduna çevirebileceğiz. VIC kontrol registeri 2 ise şu işleri yüklenir: 7-6 kullanılmaz, 5 BU BİTİ HEP 0 YAPIN!, 4 Çok renk modu (Multi color), 1 = Çok renkli
3 38/40 kolon gösterim modu, 2-0 Ekranın sağa kayma miktarı 0-7 piksellik yumuşak kaymalar bu adresle yapılır. Bu bitlerin içinde de sadece bir tanesi işimize yarıyor. Ekranı çok renkli moda geçirmek için 4. biti 1 yapmanız gerekiyor. Şimdi de hesaplaması en zor olan registere geldi sıra. Yani VIC bellek kontrol registeri: 7-4 Video matrisinin adresi, 3-1 Karakter datasının adresi, 0 Kullanılmaz. Şimdi de yukarıdaki açıklamaların tercümesine gelelim. Video matrisi dediğimiz şey, karakter ekranının kendisine verilen addır. Ekranın en tepesine yazacağınız bir A harfi, video matrisinin 0. satır 0. sütununda yer alır. Düşük çözünürlüklü moddayken (karakter ekranı kullanırken) ekranda görülen karakterlerin bellekte saklandığı yeri 7, 6, 5 ve 4. bitler belirler.
Biliyorsunuz 64K'lık bellek VIC'in kullanabileceği 16K'lık dört bölgeye ayrılmıştır. Bu 16K'lık bölgelerin her birine bir BANK adı verilir. $D018 adresindeki bitler de adresleri bir BANK için relatif (bağıl) olarak belirler. Yani $0000-$3FFF arasını kullanırken matrisin yerini $0400 olarak belirlerseniz, $C000-$FFFF arasını kullanmaya başladığınızda ekran matrisi $C400'dan başlar. Her matris 4 blokluk, yani 1K'lık yer kapladığından, sadece dört bit kullanarak 16K'lık alandaki matris yerini belirleyebilirsiniz. Eğer bu dört biti 1 yaparsanız $0400'deki matrisi seçersiniz (ki bu normalde kullanılan kombinasyondur). Bitleri 15 yaptığınızda ise $3C00'daki matrisi seçersiniz. Yalnız bitler kontrol baytının en başında olmadığı için (7-4. bitler, 3-0 değil!!) bulduğunuz sayıyı bayta koymak için 16 ile çarpmalısınız ilk önce. Bu dört bitin değerini bulmak için şu formülü kullanabilirsiniz: Yukarıda da bir “karakter datası” diye bir şeyler saçmalamışım. Konumuzun dışında ama, biraz da bunun ne anlama geldiğini açıklamak istiyorum: Demin matrisin ne olduğunu anlatmıştım. Bu matrisin her karesinde 0-255 arası bir değer bulunur. Bu değere karşılık ekrana hangi grafik bloğunun basılacağını da bir şekilde bilgisayara bildirmemiz gerekli. Yani matriste bulunan $01 baytının ekrana çıkaracağı A harfinin dataları bir yerlerde saklanıyor olmalı. İşte bu grafik bilgisinin bank içinde bulunduğu yer 3, 2 ve 1. bitler tarafından belirlenir. Her karakter datası sekiz bayt tutar. Toplam 256 karakter bulunduğuna göre bu karakter datası için 8 blok (2K) gereklidir. Bu iki kilobaytlık alanlardan sekiz tanesi bir banka sığar. Sekiz ayrı bilgiyi de sadece üç bit kullanarak kodlayabiliriz. Bu üç bitin değerini 2048 ile çarparak adresi rahatça bulabilirsiniz. Adresten bu üç biti bulmak için ise şu formülü kullanmalısınız: INT(ADRES/2048). Bu bitler de kontrol baytının tam başında yer almıyorlar. Bu yüzden baytın içinde gerekli yere getirilmeleri gerekli. Bu iş için de bulduğunuz üç bitlik sayıyı iki ile çarpmalısınız. Sonuç olarak, istediğiniz matriste yer alan karakterleri istediğiniz grafik datalarını kullanarak göstermek için şu yolu izlemelisiniz: 1. Matris adresini belirleyin (1024'ün tam katı olmasına dikkat edin). 2. Grafik datası adresini belirleyin (2048'in tam katı olmasına dikkat edin). 2.5. İlk iki adresinizin $0000-$3FFF arasında olmasına dikkat edin. 3. Matris adresini 1024'e bölün ve 16 ile çarpın. 4. Grafik adresini 2048'e bölün ve 2 ile çarpın. 5. Bu iki sayıyı toplayın ve $D018'e yazın. Bu arada VIC'in $1000 ile $2000 arasında sizin datalarınızı değil de standart karakter setini göreceğini de eklemeliyim. Bu yüzden bu alana koyduğunuz datalar grafik ekranında bile görünmez. Bu kadar bilgi içinde bize gerekeniyse sadece aşağıda anlatacağım kısmı: Grafik ekranı kullandığınız zaman $D018'in 3. biti grafik ekranının $0000-$1FFF arasında mı, yoksa $2000-$3FFF arasında mı yer alacağını belirler. Demin VIC'in belleği dört ayrı bank olarak gördüğünden bahsetmiştim. Bu banklardan hangisinin kullanılacağını (size garip gelebilir ama doğru) VIC değil, CIA 2 belirler. Yani bank seçimini bu çipe ait olan $DD00 - 56576 adresinden yaparsınız. Bu adresin 1-0 bitleri bank yerini belirler. Şimdi bitlerin değerine göre seçilen 16K'lık böl-
gelerin bir listesini veriyorum:
Ye 00
9 Ol
$C000-$FFFF $8000-$BFFF
910 $4000-$7FFF $0000-$3FFF Yukarıdaki listeden de anlayacağınız gibi normal zamanlarda bu bitlerde 11-3 değeri bulunur. Bilgisayarınızı 64K RAM konumuna geçirmek sandığınızdan daha kolay (detaylarına girmediğiniz zaman tabii ki). $01 nolu adrese değerini verirseniz tüm giriş/çıkış alanları, KERNAL ROM'lar, BASIC ROM'lar ortadan kalkar. Geriye 64K büyüklüğünde bomboş bir bellek kalır. Ama bu bellekte sadece data saklayabilirsiniz. Bu bomboş bellekte yapılacak olan ilk interrupt girişiminde de bilgisayarınız boş bir alana sıçrayacak ve kilitlenecektir. Bu yüzden RAM moduna geçmeden önce SEI komutuyla interruptları kapatmalısınız. 64K'lık RAM moduna giderken dikkat etmeniz gereken bir nokta daha var: Tüm giriş-çıkış alanlarını ortadan kaldırdığınız için VIC, SID gibi özel alanlara erişim yapmanız mümkün olmayacaktır. Bu yüzden bu bölgelerle olan işlerinizi ortalığı boşaltmadan önce halletmelisiniz. Tüm RAM ortaya çıktığında bütün yardımcı çipler son ayarlandıkları şekilde işlemlerini yapmaya devam ederler. ROM'ları ve giriş çıkış bölgelerini yerine koymak için $01'e tekrar $37 vermeniz yeterli. Bundan sonra CLI kullanarak interrupt'ları açmayı unutmazsınız sanırım.
Sıra Pratiğinde Buraya kadar sağ salim gelebildiyseniz, artık gerekli tüm temel bilgilere sahipsiniz demektir. Yazının kalanını gönül rahatlığıyla okuyabilirsiniz. Programa girişmeden önce programımızdan neler istediğimizi bir düşünelim: 1. Grafik ekranını açma: Ekranı grafik moduna geçirip, $E000-$FFFF arasının görünmesini (seçtiğimiz renk bölgeleriyle) sağlar
2. Grafik ekranını kapatma: Ekranı son bulduğu haline çevirir. Buna son kullanılan BANK'e dönmek de dahil edilmeli. 3. Grafik ekranını temizleme: $E000-$FFFF arasını temizleyip renkleri ayarlar. 4. Renk ayarlama: Üç multi color renginin 16 renk içinde hangileri olduğunu belirler. 5. Nokta basma: Üç multi color renginden biriyle nokta basar veya noktayı siler. Bu temel işlemleri yerine getirebilen bir program yazmak bile bu ayki yerimizi dolduracağından, programı geliştirmeye açık olarak tasarlamalıyız. Bunu yapmanın en kolay yolu başlangıç adresine bir “Jump Table” yani sıçrama tablosu koymaktır. Bu tablo tamamen JMP $C100, JMP $C149 vb. komutlardan oluşur. Bu sayede hem 256/3 komutluk bir program için yerimiz olur, hem de komutlar SYS49152, SYS 49155,... gibi sıralı adreslerle çağrılırlar. Biz şimdilik beş tane JMP $C100 koyalım en ba-
şa. İlk iki komut hepsi içinde en kolay olanları. İlk komutta yalnızca gerekli VIC registerlerini değiştirmemiz gerekiyor. Ama daha sonra bıraktığımız yere dönebilmek için bu registerlerin ilk değerlerini bir yerlerde saklamakta yarar var. Şimdilik bu değerleri $C0F0'dan itibaren saklayalım, daha sonra programın bitiş yerine alırız (tüm bu gariplikleri, programı adam gibi bir ASSEMBLER kullanmadan, doğrudan monitörle yazdığımızı farz ettiğim için yapıyoruz). VIC adreslerinden gerekli olanları değiştirirken, esnek bir yapı oluştarmak için baytların içinde yalnızca bize gereken bitlerle oynamalıyız. Bunu yapmak oldukça kolaydır. Önce değiştirmek istediğiniz biti bayttan çıkarırsınız (yani baytı 255-2^(bit no) ile AND'lersiniz). Mesela 7. biti değiştirmek istersek LDA bayt AND ORA programını kullanmalıyız. Bu sistemi kullanarak grafik ekranını açarız ($D011), çok renk moduna gireriz ($D016) ve video matrisinin yerini ayarlarız ($D018). Video matrisi, çok renk modundayken üç renkten ikisini belirlemek için kullanılır. Matrise ait her baytın ilk dört biti bir renk, ikinci dört biti diğer renk için kullanılır. $D800'daki renk RAM'inde de üçüncü ve son renk bulunur. Bu renk RAM'i de VIC'e ait bir bellek olduğundan, altında normal bir RAM bulunur (renk RAM'i adresleri sadece dört bit tutabilir). Ben kafanızı karıştırabilmek için $D800'ın altına matrisi yerleştirmeyi uygun buldum. Bu sayede $D800 adresinde her üç renk de tutulmuş oluyor (ilk iki renge ulaşmak için ROM'ları kaldırırsanız). İsterseniz $D018'e bu iş için yazmamız gereken biti birlikte hesaplayalım: $D800-$C000 = $1800 6144
6*16 = 96 Bir de grafik ekranı $E000'a almayı eklersek (3. bit): sonucunu buluruz. Kısacası $D018'i sakladıktan sonra LDA #568 STA $D018 komutlarıyla renklerin yerini ayarlayabiliriz. Ekranı eski haline çevirmek deminkinden daha kolay. Sadece sakladığımız baytları alıp gerekli adreslere yazarsak, grafik ekranını açmadan önce grafik durumu neyse aynen geri alınır (renkler dışında). Geldik üçüncü kısma, yani ekranı temizlemeye. Ekranı temizlemeye girişmeden önce bir şey daha öğrenmelisiniz: Eğer ROM'lar yerindeyken ROM'da olması gereken bir adrese bilgi yazmaya kalkarsanız ROM'un altında yer alan RAM'e yazarsınız bilgiyi. Bu yüzden ekranı temizlemek için ROM'ları yerinden kaldırmaya gerek yok. Kendini değiştiren bir kod sayesinde $E000-$FFFF arasını $00'la doldurmak ekranı temizlemek için yeterli olacaktır. Daha sonra $D800'a
(ROM'lar yerinde durduğuna göre renk RAM'ine) son seçilen renk doldurulur, ROM'lar kaldırılır ve $D800'a matris renkleri doldurulur. İlk ekran temizlendiğinde olarak belirlenmiş olan bu renkler ilk renk değiştirdiğinizde verdiğiniz değerleri alırlar. Bundan sonra her ekran temizlendiğinde son olarak kullandığınız renklerle temizlenir ekran. Dördüncü kısımda, yani renk değiştirme kısmında kullanıcıdan bilgi alınması gerekiyor. Bunu yapmak için virgül kontrolü ve sayı alma rutinlerini kullanabiliriz. Art arda verilen üç JSR ile $14-$15 adreslerine klavyeden girilmiş olan sayıyı düşük-yüksek değerlikli bayt formatında alabiliriz. Bu adresler sırasıyla şu isimleri alırlar: CHKCOM - $AEFD: virgül kontrol eder, yoksa SYNTAX ERROR verir. FRMNUM - $AD8A: Sayıyı alır. INTEGER - Integer'e çevirir ve $14-$15'de saklar. Bir de sayı istediğimizden büyükse ILLEGAL QUANTITY ERROR'u yaptırmak için $B248'e sıçrayabiliriz. Renk için üç rengi de klavyeden aldıktan sonra ekran temizleme rutininin renk adreslerine yazarız, yani LDA STA $D800,y İlk rengi dört bit kaydırıp ikinci rengi bununla ORA'larsak matrise yazılacak rengi buluruz. D800'da saklanan renk zaten dört bittir ve doğrudan yazılabilir. Renkleri yazma işlemi de bitince ekran temizlemenin sonundaki renk yazma rutinine sıçrayarak bu renkleri aktif hale getiririz. Bir nokta koymak için kullanılan sistemler oldukça karışık olduğu için, isterseniz bu rutini de gelecek sayımıza bırakalım. Yani gelecek sayıda detaylı olarak nokta koyma işleminin nasıl yapılacağını, formüllerin nasıl makine diline uygulanacağını, yavaşlığın sebeplerini ve bu yavaşlıktan ne gibi sistemlerle kurtulabileceğimizi anlatacağım. Bu ayın programını ve bu programı kullanan BASIC örnek programlarını döküm ekinde bulabilirsiniz. Bu programlar şu komutları kullanıyor: SYS 49152: Grafik ekranı. SYS 49155: Normal ekrana dönüş. SYS 49158: Ekranı temizleme. SYS 49161,R1,R2,R3: Renk ayarlama. R1, R2 ve R3 0-15 arası renkleri belirtir. SYS 49164,X,Y,RN: X,Y koordinatlı noktayı R rengine geçirir. Eğer R = 0 ise noktayı siler. Gelecek ay görüşmek üzere hoşçakalın.