Atölye
Retro bilgisayarMENÜ Şimdiye kadar, Makine Dilinin Püf Noktaları köşesinde ufak tefek rutinler kurcaladık. Bu rutinleri birbirine ekleyerek hoş efektler yaptık. Artık atölyemizde bu rutinlerle BASIC'i birleştirerek işe yarar araçlar yaratmanın zamanı geldi. Bu işe girişmeden önce ilk olarak yapmamız gereken, BASIC sistemini etkilemeden makine dili programı yazmayı öğrenmektir. Çünkü intro tekniklerini açıklarken kullandığımız programlama sistemleri KERNAL'ın zaman zaman kullandığı bazı adreslerle oynayarak herhangi bir BASIC programının çalışmasını engelliyordu. Oysa çok harika zamanlamaya ihtiyaç duymayan rutinler, yeterince iyi programlanırsa BASIC'e güç katabilir. Dergimizi eski sayılarından beri takip edenler, 2. sayının döküm ekinde yayınlanmış olan “Matematik Temelli Çizimler” programının makine dilini ne kadar etkili kullandığını hatırlarlar. Eğer BASIC kullanarak X ve Y'ye bağlı bir fonksiyonu üç boyutlu olarak çizmeye kalkarsanız, her fonksiyon için 12-24 saat beklemek zorunda kalırsınız. Oysa demin bahsettiğim program, en çok vakit yiyen rutinleri makine dilinde yazarak bu işlemi en fazla on dakikaya indirmiştir. Atölyemizin ilk odağında makine dilinin BASIC programlarını daha canlı, daha renkli hale getirmesini seyredeceğiz. Daha sonraki odacıklarda makine dilinde ondalıklı sayılarla işlem yapan işçilere bu işlemleri nasıl yaptıklarını soracağız. Ondan sonraki odacıklara henüz ben de uğramadım. Kalan işlemleri beraberce öğreniriz. Demin de söylediğim gibi bu ilk odacıkta ekranı daha canlı hale getirmek için neler yapabileceğimizi öğreneceğiz. “Bir konuyu anlamanın (ve anlatmanın tabii ki) en kolay yolu bir örnek üzerinde” prensibinden yola çıkarak ilk örneğimizi sunuyorum: Şimdiye kadar birçok MENU sistemi gördünüz. Genel olarak alt alta dizilen seçenek numaralarının yanına seçenekler yazılır ve kullanıcının bir sayı girmesi beklenir. Karşılaşabileceğiniz en güzel efektlerden biri, seçilmekte olan satırın negatif (reverse) yazılmasıdır. Gelin, biz aktif olan seçeneği, ekran boyunca uzanan rengarenk şeritlerle belirtelim. Şerit kullanıcının kursor tuşlarını kullanmasıyla yukarı-aşağı oynasın ve RETURN tuşuna basıldığında da bulunduğu seçeneği bize bildirsin. Temel olarak pek de zor bir şey istemiyoruz, ama en azından iki işi yan yana yaptırmalıyız bilgisayarımıza. Bir yandan gerekli yere renkli şeritleri dizerken, diğer yandan da BASIC'in kullanılmasına izin vermeli program. Bu sayede kullanıcının tuşlarını BASIC'le kolayca izleyebiliriz. Tabii ki tüm işi makine dilinde yapabiliriz, ama bir IF...THEN komutuyla yapabileceğimiz kısacık işleri neden makine dilinde yapmaya çalışalım ki? Bu örneği programlayabilmek için ilk olarak BASIC'e karışmayan ve bir satırlık çizgiler koyan bir INTERRUPT rutini yapmalıyız. RASTER zamanının çoğunu BASIC'e ayırmak istediğimiz için $D012'nin gereken yere gelip gelmediğini sürekli kontrol edemeyiz. Bu durumda geriye bir tek seçenek kalıyor, o da BASIC'in çalışmasını engellemeyecek bir RASTER interrupt rutini yazmak. Şimdiye kadar kullandığımız RASTER interrupt giriş rutinleri, bazı arkadaşlarınızın da fark ettiği gibi BASIC'i alt-üst ediyor. En sona sonsuz döngü kurmak yerine BASIC'e dönsek bile kursor ya yavaş ya da hızlı yanıp sönüyor, programların çalışması aksıyor. Bu durumda en baştan, sistemin zamanlamalarına dokunmayan bir RASTER interrupt yaratmalıyız. Aslında bir RASTER interrupt'ı yaratmak için Tablo 1'deki program yeterlidir.
RAM
ROM
MONİTÖR
TABLO 1
.,C000 SEI
LDA $30
STA $0314
LDA # $CO
STA $0315
LDA $IB
STA
LDA H $32
STA $DO12
LDA # $01
STA $DOLA
LDA & $00
STA $DCOE
CLI
RTS
BASIC'e de izin veren interrupt başlangıç rutini.
Gördüğünüz gibi bu programda
$DC0D'ye dokunmuyoruz. Çünkü bu adrese $7F verirsek, BASIC'in kendisi için kullandığı bazı interrupt'ları kapatmış oluyoruz. Introlarda neden bu adresi değiştirdiğimizi birazdan, interrupt rutinin girişini anlatırken söyleyeceğim. Bunun dışında bu rutinde size yabancılık çektirecek bir şey yok. $0314-$0315 adresleriyle interrupt rutininin başlangıç adresini, $D011-$D012 adres çiftiyle RASTER interrupt giriş satırının yerini ayarlıyoruz. $D01A'ya $01 vererek ayarlanan RASTER satırına gelindiğin-
de bir interrupt oluşmasını sağlıyoruz ve interrupt'lara izin vererek BASIC'e dönüyoruz (Zararlı yerlere elimizi bile sürmeden). Yalnız interrupt'ları bu şekilde ayarladığımızda bir problemle karşı karşıya kalırız: Interrupt rutinimize yalnızca RASTER değil, CIA 1 zamanlayıcıları da sıçrama yapar. Hatırlarsanız, bu interruptları intro'larda yaptığımız gibi kapatmamış, BASIC'in hizmetine sunmuştuk. Bu durumda, interrupt rutinimizi sadece RASTER satırına gelinmesi değil, diğer zamanlayıcıların sıfırlanması da sağlar. Yani rutinin en başında buraya gelinmesinin asıl sebebinin RASTER olup olmadığını kontrol etmeliyiz. Eğer RASTER interrupt yüzünden gelmediysek, interrupt'ın oluşma sebebi bizi ilgi- 44 lendirmiyor demektir. Bu durumda yapılabilecek en iyi şey bilgisayarın kendi pisliğini temizlemesine izin vermektir. Yani $EA31 adresine sıçrayacak bilgisayarın tuş takımını okuma ve analiz etme gibi hamallıklarını yerine getirmesini sağlamalıyız. Eğer interrupt'ın oluşmasının asıl sebebi RASTER ise, o zaman gerekli işlem neyse onu yapmalıyız. Örneğimizdeki rutinde gerekli sayıda renk şeridi koymamız ancak bu durumda gerçekleşiyor. “Teori olarak tamam da, interrupt'ın hangi sebeple oluştuğunu nasıl anlayacağız?” diye bağırmanıza hiç gerek yok. Onu da hemen açıklayacağım: Eğer interrupt rutininize girildiğinde $D019'un 7. biti (M.S.B. — Most Significant Bit - En yüksek değerli bit) 1 değerine sahipse, o zaman interrupt'ın VIC tarafından oluşturulduğunu anlarız. Yalnızca bir tek interrupt yaptırdığımız için interrupt VIC'e aitse bu interrupt'ın sebebi RASTER'dır. Bazı durumlarda VIC'e birden fazla olayın interrupt yaratmasını bildirebiliriz. Mesela RASTER'ın bir satıra varması, iki sprite'ın çarpışması veya lightpen'in sinyal göndermesi interrupt'a sebep olabiliyorsa interrupt rutininin en başında ilk olarak interrupt'ın VIC'e ait olup olmadığına bakın. Eğer VIC'inse, interrupt'ı kimin yarattığını araştırarak gerekli işlemi yapın. Daha ilerki sayılarda bu türden örnekleri de ele alacağız. Kim bilir, belki atölyenin bir yerinde bol interrupt'lı bir oyun yer almıştır. Gene konumuza dönelim. Demin BASIC ve makine dili ortak kullanılacaksa, hele bir de interrupt yapılmalıysa interrupt rutinin en başında yapılması gereken ilk işin interrupt sahibi araştırmak olduğunu söylemiştim. Örnek programın başında bunu:
Lda Bmı
RASTER'miş komutlarıyla yapıyoruz. Bmi komutu yerine:
And E $80
Bne RASTER'miş komutlarını koyabiliriz. Belki siz de bit kontrolü yaparken bu sistemi kullanmaya alışıksınızdır. Ama yukarıdaki komutlar hem A'nın içeriğini etkilemez, hem de aşağıdakinden daha hızlı çalışır. Yukarıdaki sistemde negative flag'ini (eksi bayrağını) kullanıyoruz. Bu bayrak, kendisini etkileyen bir komut kullanıldığında (LDA gibi) bu komutun kullandığı değerin MSB'sinin değerini alır. Daha sonra kullanılacak olan bir BMI (branch on result Minus — sonuç eksiyse dallan) MSB birse, BPL (Branch on result Plus — sonuç artıysa dallan) MSB sıfırsa işlem yapar. Bu bite neden eksi biti dendiğini öğrenmek için biraz sabredin. Örneğimize geri dönersek, $D019'un son biti birse (VIC interrupt'ıysa) $C038'e sıçranıyor. Değilse KERNAL'a izin veriliyor. Buraya kadar hep yeni şeyler öğrendik atölyemizde. Şimdi ise o kadar aydır devam eden Makine Dilinin Püf Noktaları yazısının konularından yararlanma vakti geldi. Hepimiz en zahmetsiz şekilde kaç RASTER satırlık renk koyulabileceğini biliyor sanırım. Sen! Gözlükleri olan, söyle bakalım... Duyamıyorum seni. Ne? Demek elektrikler kesikti çalışamadın, ha? Sana ödev veriyorum, makine dilinin püf noktalarını daha dikkatli oku, öyle gel. Biz arkadaşlarla devam edeceğiz. En zahmetsiz şekilde ardışık yedi RASTER satırlık renk şeridi koyulacağını hatırladık sanırım. Bunun sebebi ise, her sekiz satırda bir (doğal hayatına karışılmamış bir bilgisayarda) görüntü işlemleri için bizim zamanımızdan birazının bilgisayar tarafından çalınmasıdır. Bu yüzden bu satırlara (DMA satırları) geldiğinde kurmuş olduğumuz tüm zamanlama çöker. Saatlerce zamanlama tutturmaya uğraşmaktansa iki DMA satırı arasını kullanırız sadece, olur biter. Biraz tembellikten, biraz da görsel etkiler yüzünden bu örnekte bu yedi satırın yalnızca altısını kullanacağız. Harfler yedi piksel (nokta) yüksekliğinde olduğundan, renkleri ortalamak için bunların beşini renkle, altıncısını ise ekran rengiyle harcayacağız. Sonuç olarak renk şeritlerimiz değişik beş renkten oluşacaklar. Bu beş renk karakter setinin tam ortasına gelecek şekilde ayarlanmış olacak (RASTER satırı buna göre ayarlanmalıdır). Sonuç olarak beş rengin bir karakterin tam ortasından geçmesini sağlayacak olan rutini Tablo 2'de görebilirsiniz.
Kısacık bir rutinle BASIC ekranlarına canlılık katabiliriz.
Programda sırasıyla şu işlemler yapılıyor (hoş, çoğunuzun bunu anlamış olması gerekiyor): adresinde ilk olarak rengin değiştirilebilmesi için uygun bir yere gelinmesi bekleniyor. Eğer yerini iyi ayarlayamazsak ekrandaki renkler titrer. Sonra kaçıncı rengin gösterileceğini ayarlayan sayaç (Y registeri) sıfırlanıyor ve ilk renk $C028 adresinden alınıyor. Bu renk hemen çerçeve ve ekrana veriliyor. $C048 adresinde alt satırın başına kadar bekleniyor, sayaç veriliyor. $C048 adresinde alt satırın başına kadar
TABLO-2
LDA —$DO19
BMI $C038
JMP $EASI
.,C038 LDX # $06
»CO3A DEX
BNE $Co3Ü
LDY # $00
.,C0O3F LDA $C028,Y
STA $DO20
STA $DO21
STA $DO21
:,C048 LDX H $08
DEX
BNE $CO4A
NOP
NOP
INY
CPY # $05
BNE — $CO3F
LDA — #$00
STA
STA
$D019
SEA81
INC
JMP
bekleniyor, sayaç artırılıyor ve son renk konmamışsa renk koyma işlemine devam ediliyor. Tüm renkler koyulduktan sonra ekran rengi sıfırlanıyor. $D019 adresi daha önceleri de yaptığımız gibi artırılıyor ve interrupt'ın bittiği haber veriliyor. Son olarak da $EA31 adresine sıçranıyor. Burada da intro tekniklerinden biraz saptık gördüğünüz gibi. $EA31 değil $EA31'e sıçrıyoruz ki zavallı bilgisayar istediği gibi işlem yapabilsin. Buraya kadar tüm işlemler makine dilini ilgilendiriyor. Oysa bizim size olan sözümüz, tamamen BASIC kontrollü bir renk şeridi yapmaktı. Ama rutin ne yazık ki sabit bir koordinata renk şeridi koymaktan öteye gidemiyor. Ya da alışık olmadığınız için size öyle geliyor. Bu program, üzerine hiçbir makine dili ek yapılmadan BASIC tarafından kontrol edilebilir. İsterseniz şimdi de BASIC kullanarak bu programın nelerini kontrol edebileceğimizi bir inceleyelim: İlk olarak değiştirilebilecek şey renk şeritleri dışındaki tüm ekranın rengi. Rutinden de görebileceğiniz gibi, beş renklik şerit verildikten sonra ekran ve çerçeve rengi siyah yapılıyor. Bu işi yapan komutlar ise adresinden başlıyorlar. Eğer biz $C055 adresinde bulunan değere bazı POKE'lar verirsek, ekranın rengi artık bu değerin renginde olacaktır. Yani:
SYS 49152
komutundan sonra:
POKE 49237,1
komutunu verirsek renkli şeritlerden başka her yer beyaz olur. Bundan başka renk şeritlerinin bulunduğu tabloyla oynayarak beş rengi değiştirebiliriz. Ekranda şeritler varken 49192-49196 adreslerine şu değerleri verin mesela: 6-14-3-14- 6. Ekran rengi de siyaha ayarlayın. Bu sayede mavi tonlarından oluşmuş bir renk çubuğunuz olur. İsterseniz bu renkleri sürekli değiştirerek parıldayan bir çubuğa sahip olabilirsiniz. Tüm ekranı REVERSE (negatif) boşlukla doldurur, daha sonra da harfleri de REVERSE yazarsanız, renkli şeritler ekranda değil harflerin içinde görünür, bu sayede menü elemanlarınızın harflerinin şeritli şeritli olmasını sağlayabilirsiniz. Ama bu sefer çerçevede yer alan renkler kötü bir görüntü oluşturacağından, rutinde bulunan tüm
$D020'leri $D021 gibi bir adrese çevirin. Mesela $D027 yaparsanız, bu bölgedeki birinci sprite'ın içinden renk şeritleri geçer. Bu kadar şey anlatmama rağmen, bu rutin hâlâ menü elemanların seçmekte kullanılamaz. Çünkü ekranın tepesinde sabit bir şekilde duruyor. Ne yapmalıyız ki bu garip şerit yerinden oynasın? Bu sorunun cevabını RASTER interrupt yapan herkes biliyor aslında. RASTER interrupt'ı yaparken interrupt'ın bizim istediğimiz satıra gelindiğinde yapılmasını $D012 adresine yazarak sağlamıyor muyduk? Bu işi interrupt adreslerini ayarlarken, ya da interrupt'ın içinde ya da herhangi bir programdan yapabiliriz. Bu konuda bizi kısıtlayabilecek herhangi bir kural yok. Öyleyse serbest serbest dolaşırken:
POKE 53266,66
komutunu verirsek ne olur? Tabii ki interrupt rutini verdiğimiz RASTER satırına gelindiğinde devreye girer. Kısacası renkli şeridimiz 66 RASTER satırına kayar. Ama burada bir büyük problemle karşı karşıyayız: renk şeritleri ancak belli bir konumda başlarsa DMA satırlarını atlatabiliyor (bu rutin DMA satırında RASTER interrupt yapmalıdır mesela). Eğer bu konumdan farklı bir yerde başlarsa mutlaka renkler sağa sola oynar, sabitlik bozulur ve çok kötü görüntüler oluşur. Bu kötü görüntüleri engellemek için RASTER satırını belli bir kurala göre ayarlamalıyız. Bu kuralı rutinin başlangıç RASTER satırından çıkarabiliriz. Genel olarak, n. RASTER satırında çalışan her rutin n+8. RASTER satırda da hatasız olarak çalışır (çok harika zamanlamalarla uğraşmıyorsa ve üzerinde sprite yoksa). Bu kural en azından buradaki program için geçerli. Rutin orijinal olarak $32—50 RASTER satırından başlıyor ve 0. satırda yer alıyor. O zaman bu şeridi n. satıra koymak için:
POKE 53266,504 9*8
komutunu vermelisiniz. Bu sistemle şeritleri ekranın tüm satırlarında dolaştırabilirsiniz. Eğer BASIC'de basit menüler yapabiliyorsanız, artık bu menülerde kontrollü renk şeritleri dolaştırmamanız için hiçbir neden kalmadı. Belki çoğunuz buraya kadar olan bilgilerin işinizi yapmak için yeterli olduğunu düşünüyorsunuz, ama bir açık nokta kaldı ki, ancak menülerinizi düzenlerken farkedebilirsiniz. Diyelim ki kullanıcı şeridi seçilecek satıra getirdi ve RETURN'e bastı (ya da siz ne istediyseniz onu yaptı). Kullanıcının seçtiği işlemler yapılırken bu şeridi ne yapacağınızı hiç düşündünüz mü? Belki ekranın üstüne ya da altına yerleştirerek ortada görülmemesini sağlarsınız, ama şeridi tamamen ortadan kaldırmak için ne yapmalıyız? Bu sorunun cevabını bu sayıda vermeyeceğim. Bu konudaki cevaplarınızı bekliyorum. Ne yazık ki bu soruyu bilirseniz bir ödül kazanamayacaksınız, ama adınız gelecek ay dergide yayınlandığında kız arkadaşlarınızı (ya da erkek arkadaşlarınıza) hava atabilirsiniz. Hem de ilerde olabilecek yarışmalar için iyi bir antrenman olur. Düşünün bakalım. Cevaplarınızı bekliyorum. Tablo 3'de basit bir BASIC menü seçicisi var. Ama pratik olarak pek de iyi bir ekran düzeni yok. Yalnızca size şeridi kontrol eden
BASIC programın neye benzeyeceğini göstermek amacıyla yazdım. Makine dili programın MDE çıktısını da Tablo 4'de görebilirsiniz. Bu kadarcık bir programı yazmak onbeş dakikadan fazla almaz sanırım.
Bu arada, eğer bu programları geliştirirseniz veya hoş programlarda kullanırsanız, arkadaşlarınızla paylaşmak için dergimiz adresine kaset veya diskette yollayabilirsiniz. Gelecek ay daha ilginç bir tezgahta buluşalım...
ÖZÜR: Geçen ayki Makine dili- şıklıklar sebebiyle yayımlanmamışnin püf noktaları yazısının ondalık tır. Bu programı aşağıda bulabilirsayıya çeviren programı, bazı karı- siniz. PROGRAM : ONDALIK
PROGRAM
te
he be ve ve
ONDALIK
CO0O0O COBC