Bu sayfadaki yazılar
Sayfanın metni
Sayfa 56
Sonsuz döngü komutuna kadar böyle gelince, buradaki komutların hepsine uğrandığına dair emin olduktan sonra daha detaylı incelemeye karar verdi. Tekrar g c000 yaparak başa döndü.
Bu sefer debugger'ın registers penceresini de açtı. Bütün komutları tek tek işletirken bir yandan da her komuttan sonra registerların değerlerine bakıyordu. (Vice'ın Linux versiyonunda maalesef ayrı bir register penceresi yoktur. Debugger konsolunda registers komutu vererek registerlar listelenebilir. Dolayısıyla satır satır ilerleyip her satırdan sonra registerlara bakma için sırayla bir Step-In bir registers komutu vermek gerekiyor. Neyse ki ilk defa bu komutları kullandıktan sonra, yukarı ok tuşunu kullanarak son kullanılan komutlara erişmek mümkün)
Şekil 2. Debugger Registers Penceresi
Sonunda tam sta $0314 komutuna geldiğinde A registerinde garip bir değer gördü. Daha bir önceki satırda 0 yüklenmesine rağmen şimdi A registerinde $2f değeri vardı. Bir önceki satıra tekrar baktı:
lda $00
Birden kafasında şimşek çaktı. Bu komut akümülatöre 0 yüklemiyordu. Aksine 0. adresten okuduğu değeri yüklüyordu. Yani adresleme modu yanlıştı. Immediate adresleme modu yerine sıfırıncı sayfa adresleme modu çalışıyordu. Hemen komutu düzeltti.
lda #$00
Zaten bir altındaki satırda da aynı hatayı yaptığını fark etti ve onu da düzeltti. Hemen acme ile yeniden derleyip Vice ile çalıştırdı.
Sonuç hüsrandı. Yine boş ekran ve ready yazısına dönmüştü makine. Hemen çıkıp bir daha derledi ve çalıştırdı sonuç aynıydı. Yalnız bu sefer ekranda ready mesajından önce küçük beyaz bir flaş olduğunu fark etti. Bu iyiye işaretti. Acaba bir şekilde IRQ rutinindeki beyaz çizgi koduna varıyor muydu sistem.
Hemen Vice monitörüne girip yine IRQ rutinine breakpoint koydu ve programı çalıştırdı.
break c100 g c000
Debugger breakpoint'te durdu. Yani sistem başarıyla interrupt'a gelebilmişti. Sistem interrupt'ı düzgün kurduktan sonra her ekran taramasında yeniden c100'deki breakpoint'e yakalanmalıydı. Daha detaylı bakmadan önce tekrar yakalanacak mı diye kontrol etmek için programı devam ettirmeye karar verdi. Bunun için debugger'dan çıkış komutunu verdi:
exit
Bu komutla beraber program devam etti ve kendisini ready yazısında buldu. Demek ki IRQ rutinine sadece bir kere giriliyor sonra IRQ rutininde yaşanan bir problemden dolayı bir daha girilemiyordu. Bunun üzerine IRQ'dan çıkışı kontrol etmeye karar verdi. Alt-M ile tekrar monitöre girip kernel'de atladığı IRQ çıkış rutinine breakpoint koydu.
break $ea8l g c000
Program önce daha önceden koyduğu c100'deki breakpoint'te durdu.
exit
Bu sefer program ea81 adresinde durdu. Burada art arda z komutuyla ilerlerken karşısına RTI komutu çıktı. Bu komutla CPU IRQ işlemekten çıkacak ve normal rutine yani bu programda ihtimalen c003 adresindeki sonsuz döngüye dönecekti.
Fakat z demesiyle beraber kendini alakasız bir adreste buldu. Karşısına BRK komutu çıkmıştı. Yani program IRQ'dan düzgün şekilde dönmüyordu.
Interrupt'tan dönerken olanları düşündü. RTI komutuyla işlemci stack'ten döneceği adresi alıyor ve oraya atlıyordu. Bu program yanlış yere atladığına göre stack'ten yanlış adresi alıyor olmalıydı. Ama stack nasıl bozulabilirdi. Hemen IRQ rutini için yazdığı koda bir daha baktı. Ve orada PHA komutunu gördü.
"Aaaah ben d020'deki değeri stack'e atıp beyaz çizgiden sonra geri stack'ten okuyacaktım." Evet başta böyle tasarlamıştı. Ama sonra bunu unutup d020'yi eski rengine döndürmek için PLA ile stack'ten değeri okuyacağına LDA ile direkt yüklemeye kalkmıştı. Bunun sonucu olarak, IRQ'ya girilirken stack'teki en üst iki bayt dönüş adresi oluyor fakat çıkış esnasında aradaki PHA ile gönderilen bayt hiç PLA ile geri çekilmediği için en üst iki bayt dönüş adresi baytlarından biri ile d020'nin PHA'lanmış rengi oluyordu. Bu da yanlış adres demekti. Hemen gidip lda #$0e satırını sildi ve yerine pla komutunu koydu:
pla sta $d020
Hemen derleyip yeniden çalıştırdı. Ve bu sefer karşısına beyaz bir çizgi çıktı. İşte artık IRQ çalışıyordu. Fakat çizgi çok kalındı.
Klavyeyle gezinmek için ← ve → tuşları.
Sayfa 57
Gecikme değeri olarak sadece $0a koymuştu oysaki. Ama artık içi rahattı. Bu raster çizgisinin çıkmamasına göre çok daha küçük bir hataydı. Elbet bulunurdu.
Hemen gecikme döngüsünü tekrar inceledi. Çok geçmeden hatayı gördü. Yine # karakterini unutmuş ve yanlış adresleme modunu kullanmıştı.
lda #$0a
ve tekrar derlediğinde artık programı çalışıyordu.
Vice komutlarının özeti
«break c000 : $c000 adresine breakpoint koy : $c000 adresinden kodu çalıştırmaya başla * Z: (breakpointe gelip durduğunda) Step-In . Step-Over * Tet: Fonksiyondan geri dön
* exit : debuggerdan çıkıp sonraki breakpointe rastlayana kadar normal çalışmaya devam et
* registers: registerların o anki değerini göster
. m c000 göster
1: c000 adresinden başlayarak bellekteki baytları
.« d c000 : c000 adresinden başlayarak kodunu listele
Şekil 3. Disassembly Penceresi
Sık Yapılan Hatalar
Bazı basit hataları nedense en tecrübeli programcılar bile sıklıkla tekrar tekrar yaparlar. Bunlardan bazıları aşağıda. Eğer programınız çalışmıyorsa ilk arayacağınız hatalar bunlar olmalı. Yaptığınız hataların en az %50'si bunlar olacaktır.
* Unutulan #: Bunu örneğimizde de gördük
* Stack hataları: Dengesiz push ve pop komutları. Eğer bir IRQ rutininde veya alt rutinde pha ve pla komutlarının sayısı eşit değil ise, yani başka bir deyişle stack'e PHA ile koyduğunuz her değeri geri almıyor veya fazladan değerler alıyorsanız. Programınız RTS veya RTI komutuna rastladığında yanlış yere atlayacaktır. Bunun sebebi de daha önce de belirttiğimiz gibi dönüş adresinin stack'te tutulması.
* İndex hataları: İndexli adresleme kullanırken (lda $c800,x gibi) iki şeyi kontrol ettiğinizden emin olun. Bu komutlar taban adresinin yanlış olduğu durumlarda veya X registerinin beklenmedik bir değer aldığı durumlarda yanlış çalışırlar. Genelde okunan tablo ebadı gözden kaçabilir. Örneğin c800 adresinden başlayan 32 baytlık bir tablonuz varsa X registeri de 0 ile 31 arasında olmalıdır. Eğer X registerindeki değer başka bir matematiksel işlemle hesaplanıyorsa bu işlemin sonucunun 0-31 arasında kalıp kalmadığını kontrol etmelisiniz
* Karşılaştırma hataları: Özellikle C64 ile ilk programlamaya başladığınız zamanlarda koşullu dallanma komutlarını birbiriyle karıştırabilirsiniz. BNE, en çok kullandıklarınız olduğu için fazla karışmaz fakat, BPL ile BCC'yi karıştırabilirsiniz bu komutların anlamlarını tam olarak anladığınızdan emin olun
Unutulan inc $d019: VIC IRQ'larını kullanırken, IRQ rutini içinde inc $d019 ile VIC'e IRQ isteminin işlendiğini bildirmezseniz IRQ rutininiz sadece bir kere çalışır
* Kendini değiştiren programlar yazarken yanlış baytı değiştirme: Genelde C64'te hız optimizasyonu olarak kendini değiştiren kodlar yazmak sık kullanılan bir tekniktir. Bunların debug edilmesi genelde daha zordur. Eğer programınız beklemediğiniz şekillerde kilitleniyorsa kodun kendi kendini değiştirdiği noktaların yakınlarına breakpointler koyarak oraları adımlamalısınız. Örneğin aşağıdaki koda bakın
ldx value lda jmpTable lo, x sta jumper lda jmpTable hi, x sta jumper 1
jumper: jmp $0000
Bu kod val değerine bakarak bir adrese atlamaya karar veriyor. Yani değişik val değerlerine göre değişik yerlere atlayacak. Fakat bunu denerseniz çalışmayacak ve debug ederseniz, jmp komutunun bozulduğunu göreceksiniz. Bunun sebebi jumper adresindeki ilk baytın JMP komutunun kendisi olması. Değişmesi gereken baytlar aslında jumper ve jumper+1 adreslerinde değil, ve adreslerinde yer alıyor.