Şimdi buraya kadarki teorik bilgileri kullanarak ilk programımızı yazacağız. Bu programda C64'ün en klasik ve basit efektlerinden olan Raster Çizgileri ile tanışacağız. Aynı zamanda bu programı yaparken 6510'u kullanarak VIC'e “XX'inci satıra gelince beni uyar” demeyi öğreneceğiz. Yani VIC IRQ'larını programlamaya başlayacağız. Kocaman bir efektler dünyasının kapısını aralamak üzeresiniz. 25 yıldır tükenmeyen bir dünyanın...
Tipik bir VIC IRQ programı ile başlayalım.
!to "raster0.prg"
*=$c000
;; ------------------------------------------------
Baslangic:
jsr RasterIRQHazirla
Son:
jmp Son
;; ------------------------------------------------
RasterIRQHazirla:
sei
lda #$7f
sta $dc0d
lda $d01a
ora #$01
sta $d01a
lda $d011
and #$7f
sta $d011
lda #$20
sta $d012
lda #<IRQRutini
sta $0314
lda #>IRQRutini
sta $0315
cli
rts
;; ------------------------------------------------
IRQRutini:
inc $d019
lda #$01
sta $d020
lda #$00
sta $d020
jmp $ea81
;; ------------------------------------------------
Bu programda olan biteni inceleyelim.
Baslangic:
jsr RasterIRQHazirla
Son:
jmp Son
Aslında bu bölüm sadece kodun düzenli olması açısından var. Programın ana rutini diyebiliriz buna. Programımız ana rutininde önce IRQ hazırlayan alt rutine atlayıp geri dönüyor ardından da sonsuz bir döngüye giriyor. Yani 6510 normalde aynı komutta takılıp kalıyor. Sadece VIC'ten kesinti isteği geldiği zamanlarda geçici olarak IRQ rutinindeki işleri yapıyor ve o rutin bitince tekrar bu sonsuz döngüde kalmaya devam ediyor.
RasterIRQHazirla:
sei
6510 içinde “Dışarıdan Gelecek Kesinti İsteklerini Bloklama” imkanı mevcut. Bunun için Durum Registerinde Interrupt Flag adlı bir bit var. Bu bit 1 yapıldığı zaman 6510 IRQ pinine sinyal gelse bile kesinti uygulamaz ve hiçbirşey olmamış gibi devam eder. Sei komutu işte bu bit'i 1 yapar. Tersi olan cli komutu ise bu biti 0 yaparak bundan sonraki interruptlara izin verir. Yani sei ve cli komutlarının arasındaki komutlar çalışırken başka bir interrupt sinyali gelip de 6510'un herhangi bir yere atlama şansı yoktur. Bunun neden önemli olduğunu birazdan göreceksiniz.
lda #$7f
sta $dc0d
C64 içinde 6510'a kesinti isteği gönderebilen tek çip VIC değil. Disket sürücü, klavye gibi pekçok çevre birimini kontrol eden CIA çipleri de 6510'a kesinti isteği gönderebiliyor. Normalde C64 ilk açıldığında Kernal'deki başlangıç rutini içinde CIA çiplerinde bulunan timerlardan biri programlanır ve bu timer her 20 ms'de bir 6510'a kesinti isteği gönderir. Bu kesinti isteği ile beraber 6510 yine ROMdaki başka bir bölgeye atlar ve bazı rutin işlerle ilgilenir (klavyeyi kontrol etmek, cursoru yakıp söndürmek gibi). Bizim programımızda bu rutin hizmetlerin hiçbiri ile ilgilenmediğimiz için bu kesinti isteğinin gelmesini engellemek istiyoruz. Bunun için isteği gönderen CIA çipine “bana IRQ gönderme” dememiz gerekiyor. CIA çıpının ayrıntıları konumuz dışında. Fakat bu iki komutun bu işe yaradığını bilin yeter.
lda $d01a
ora #$01
sta $d01a
Burada ise VIC çipine “Bana her yeni sayfada X'inci satıra gelince haber ver” demek için gereken adımları atmaya başlıyoruz. Bu adımlar şöyle:
VIC'de Raster IRQ fonksiyonunu aktifleştirmek
Raster IRQ sinyalinin gönderilmesini istediğimiz satırı belirtmek
Bu adımlardan ilki için VIC'in $d01a adresindeki registeri kullanılıyor. Bu registerin en küçük biti Raster IRQ aktifleştirmeye yarıyor. Diğer bitler başka koşullarda oluşan IRQ'ları etkilediği ve biz onları değiştirmek istemediğimiz için bu üç komutu kullanıyoruz. Böylece diğer bitlerin değerini değiştirmeden sadece en küçük biti 1 yapıyoruz.
lda $d011
and #$7f
sta $d011
lda #$20
sta $d012
Bu komutlarla da ikinci adım gerçekleştiriliyor. Ne olduğunu anlamamız için biraz düşünmemiz lazım.
VIC Cipinin monitöre gönderdiği görüntü PAL sistemlerde tam 312 satırdan oluşuyor. Buna ekranın üstündeki ve altındaki Çerçeve bölgeleri de dahil. Dikkat ederseniz 312 sayısı tek bayt ile ifade edilemeyecek kadar büyük bir sayı. Bu büyüklükteki sayıları ifade etmek için gereken en az bit sayısı 9. 9 bit ile 512'ye kadarki sayılar ifade edilebilir. İşte bu yüzden VIC'e hangi satırda IRQ istediğimizi belirtmek için 9 bit göndermek gerekiyor. Bu 9 bit de VIC'in $d012 adresindeki registerinde bulunan 8 bit ve $d011 adresinde bulunan registerin en üst bitinden oluşuyor. Yani eğer 256'dan küçük bir değer yazmak istersek, $d011'in en üst bitine 0 yazıyoruz. Bu örnekte olduğu gibi.
d011 ve d012 VIC içindeki en hayati önemli registerler arasında. İkisinin farklı farklı ve beraber kullanımlarından inanılmaz efektler ortaya cıkıyor.
d012 yazıldığında ve okunduğunda farklı anlamlara gelen bir register. Okuduğumuz zaman bize VIC'in o an ekrana hangi raster satırını göndermekte olduğunu söylüyor. Yazdığımızda ise, eğer Raster IRQ aktifleştirilmiş ise (d01a ile) IRQ'nun olmasını istediğimiz satırı VIC'e belirtmiş oluyoruz. VIC bu belirttiğimiz satıra gelince IRQ sinyali gönderecek.
Böylelikle VIC'in istediğimiz satırda 6510'a IRQ göndermesini hazırlamış olduk. Peki bu IRQ sinyali geldiğinde 6510 ne yapacak. Önceki bölümlerde anlattığımız gibi 6510'un o an yaptığı işi bırakıp (ki bizim programımızda o an yaptığı iş sadece bir sonsuz döngü) özel olarak olmasını istediğimiz şeyi yapmaya başlaması lazım. Bunun için aşağıdaki komutları kullanıyoruz.
lda #<IRQRutini
sta $0314
lda #>IRQRutini
sta $0315
Böylelikle IRQ gelince olmasını istediğimiz şeyler için bir rutin yazıyoruz ve bu rutin bu örnekte IRQRutini adresinden başlıyor.
6510 IRQ sinyali aldığı zaman eğer IRQ biti 1 ise ROM'da bazı işlemler yaptıktan sonra bellekte $0314 ve $0315 adreslerinde alt ve üst baytı bulunan adrese atlar. Biz de burada $0314 ve $0315 içine IRQ rutinimizin başlangıç adresini yazıyoruz. Böylelikle 6510, VICten gelen IRQ sinyalini alınca bizim IRQ rutinimize atlayacak.
cli
rts
Artık bütün hazırlıkları tamamladığımız için cli komutu ile IRQ sinyallerini yeniden dikkate almaya başlayabiliriz. Eğer sei ve cli kullanmasaydık ne olurdu. Düşünün tam biz $0314'e IRQ rutinimizin adresinin alt baytını koyduktan sonra herhangi bir sebepten IRQ sinyali gelse 6510 $0314 ve $0315'teki adrese atlamak isteyecek. Oysa bu iki bayttan yalnızca biri dogru. 0315'i henüz yazmadık çünkü. Böylece 6510 alakasız bir adrese atlayıp büyük olasılıkla da kilitlenecektir. Bunun olmaması için biz IRQ koşullarını ve adreslerini değiştirirken geçici olarak IRQ sinyallerini görmezden geliyoruz. cli'nin hemen ardından rts ile ana programa dönülüyor.
IRQRutini:
inc $d019
lda #$01
sta $d020
lda #$00
sta $d020
jmp $ea81
Burada ise IRQ rutinini görmekteyiz. Rutin gerçekten çok basit bütün yaptığı çerçeve rengini önce beyaz yapıp hemen ardından da siyah yapmak. Bu rutinden sonra bütün ekran boyunca cerceve rengi siyah kalmaya devam edecek ve VIC yeni bir sayfayı monitöre gönderirken tekrar $20.satıra geldiğinde 6510 bu rutine girecek.
Bu rutinin sonucu olarak siyah çerçeve içinde tepede bir yerde kısa bir beyaz çizgi göreceğiz.
ea81 adresi ROM'da bulunan bir rutinin adresi bu rutinde IRQ ilk olduğunda yapılan işlemlerin tersleri yapılıyor ve CPU kesinti modundan çıkıp IRQ sinyali geldiği anda yapmakta olduğu işe dönüyor. Dolayısıyla biz bir miktar ilerleyene kadar ki örneklerimizde IRQ rutininden dönmek için hep jmp $ea81 komutunu kullanacağız.
Bir de en başta inc $d019 komutu var. Bu ne işe yarıyor diye merak ediyorsunuz. VIC ve 6510 arasındaki plastik topu hatırlayın. İşte bu komut ile 6510, VIC'e plastik topu geri veriyor. VIC'in d019 adresindeki registeri VIC tarafından oluşturulan IRQ sinyallerine karşı 6510'un “Hmm tamam. IRQ sinyalini aldım ve işledim. Bundan sonra tekrar olursa tekrar bana haber ver” demesini sağlıyor. Daha önce de belirttiğimiz gibi, VIC çeşitli IRQlar sinyalleyebildiği için 6510 da bu farklı IRQlardan hangilerini işlediğini ayrı ayrı bildirmek durumunda. Bu yüzden $d019 içindeki farklı bitler farklı IRQları işlediğimizi bildirmek için kullanılabiliyor. d01a da olduğu gibi ilk bit Raster IRQ biti. d019 ilk bitine 1 yazarsak VIC'e Raster IRQ sınyalını aldığımızı ve gerekeni yaptığımızı söylemiş oluyoruz.
d019 aynı zamanda VIC IRQ sinyalini 6510a göderdiği anda ilgili bitini sıfırlıyor. Yani bu bit 1 iken VIC d012'de yazılı olan satıra geliyor. IRQ sinyali gonderiliyor ve hemen bu biti VIC 0 yapıyor. Ardından 6510 IRQ sinyalini işledikten sonra onu tekrar 1 yapıyor.
Dolayısıyla Biz IRQ rutinimize girdiğimiz anda $d019'da 0 yazdığını biliyoruz. Bu yüzden inc komutu verdiğimizde aslında dolaylı olarak o biti 1 yapmıs oluyoruz. Bunun yerine lda #01 , sta $d019 da diyebiliriz. Fakat bunun yerine pek çok programcı inc komutunu kullanır. Burada bunu kullanmamızın sebebi, başka programcıların kodunda bunu görürseniz şaşırmayın diye.