Sağolsun Özay'ın hediye ettiği kobay / kobaylar geldikten sonra tekrar el attım poor man's dma v2'ye zira artık iş Noflash'lıktan maalesef çıktı. Geçen ay elime geçen eeprom'ları da kullanma fırsatı oldu bu. Ultraviyole takılmak zorunda kalmıyorum artık. Bendeki eeprom'lar 32k ancak bunlar 64k olanlar ile pin uyumlu. A15 32k'lık entegrelerde programlama voltajına denk geliyor. Çok farkediyor mu bilmiyorum ben low'da tuttum.
Kartuş rom'unda duracak yazılımı hali hazırda yazmıştım. Bir tane fail safe bir tane de biraz daha hızlı ama daha karmaşık olan şeklinde.
Özay'ın switch'li kisscart'ından ekstradan NMI / IRQ / EXROM / RESET / GND hatlarını arduino'ya bağladım. (NMI ve IRQ hatlarına 100nf filtre için kondansatör de bağladım)
1. Başlangıçta arduino c64'ü resetliyor. Exrom low'da yani kartuş devreye girecek.
2. Reset sonrası Kartuş romundaki rutin kernal'in yapacağı initialization işlemlerini yapıyor. Peşinden bir loader rutinini kaset buffer'ına kopyalıyor. Ve peşinden buna dallanıyor.
3. Loader rutini CIA'den ve VIC'den gelecek interrupt'ları kapatıyor. Ekranı kapatıyor zira ekran açık olursa badline'lardan dolayı interrupt'lar çalışırken bile vic araya girip zamanlamayı dağıtabilir. 1 portundaki bellek yönetimi register'ından kernal ve basic rom'larını da kapatıyor. (I/O'yu da kapatabilir aslında, henüz denemedim)
4. Loader rutini IRQ ve NMI vektörlerini benim rutinlerime ait olanlarla değiştiriyor. Bunlar veri transferi için kullanılacak.
5. Bundan sonra loader rutini overflow flag'ini clear edip peşinden overflow flag'i clear ise aynı satırda beklemeye başlıyor. Başka herhangi bir flag de olabilirdi hiç bir önemi yok, maksat düşük cycle harcayacak bir komut üstünde 6510'u bekletmek. Dallanan bir branch komutu 3 cycle yiyor. Yani interrupt geldiğinde 6510 en fazla 3 cycle bekleyecek elindeki işi tamamlamak için.
İşin sonrası arduino ve interrupt handler'lar arasında.
6. Öncelikle arduino exrom hattını high'a çekip $8000-$9FFF aralığını rom olmaktan çıkarıyor.
7. İki tane rutin yazdığımdan bahsetmiştim biri fail safe (yani sıçmayacak) biri de hafif optimize. (Hafif optimize çünkü daha iyisi yapılabilir, ben fazla uğraşmadım şimdilik)
Sid player'da daha önce bahsettiğim gibi 6502 kullanıyorum ve 6502 üstünde SO diye bir pin var, byte bazlı yahut daha büyük bloklar için senkronizasyonu sağlamak için ideal bir pin. Hatta ve hatta tek başına bu pin üstünde modülasyonla bile senkron veri aktarımı mümkün. Ancak 6510 üstünde SO yok ve olsa da benim senkron bir çözüm yapmaya niyetim yok zira senkron demek zamanlamayı tutturmak demek, arduino tarafında da cycle saymak demek vesaire vesaire..
Fail safe ve yavaş metod olarak benim ilk aklıma gönderilecek byte'ın değeri kadar NMI yapmak NMI içinde X register'ını arttırmak. IRQ ile de her bir byte gönderimini sonlandırmak geldi. Bunu uyguladım, hakikaten çalıştı da. Aşağıdaki videoda bu yöntem kullanıldı.
Bir diğer yöntem olarak aklıma yine buna benzer ancak biraz daha optimize bir çözüm geldi. Bunda bir byte'ı 3'e bölüyorum, her bir parçanın sayı değeri kadar NMI yapıp peşine parçayı tamamlamak için IRQ yapıyorum. Yükleme hangi adrese yapılacak, kaç blok yüklenecek gibi bilgileri ilk yönteme göre gönderiyorum. Asıl datayı ise bu ikinci yönteme göre gönderiyorum. Tek bir IRQ handler yok bu arada. Bir durum makinesi (state machine) gibi çalışan birden fazla IRQ handler mevcut.
4 tane irq handler var,
i. SlowIrq : İlk yönteme göre transfer yapıyor, işi bitince artık sıra FastIrq1'de diyor. Irq vektörünü değiştiriyor yani.
ii. FastIrq1 : Gönderilen byte'ın en anlamlı 3 bit'ini alıyor. İşi bitince FastIrq2'yi irq handler olarak tayin ediyor.
iii. FastIrq2 : Gönderilen byte'ın sıradaki 3 bit'ini alıyor. Bir byte'a
D7 D6 D5 D4 D3 D2 D1 D0 bitlerinden oluşuyor dersek bu handler D4 D3 D2'den oluşan kısmını alıyor.
iv. FastIrq3 : En ağır işle uğraşan da bu. Kalan son iki bit'i (D1 ve D0) alıyor. Tüm byte alındığı için bu byte'ı saklaması gereken yere saklayıp transferin bitip bitmediğini kontrol ediyor. Transfer bitmemişse irq handler olarak FastIrq1'i set ediyor. Bitmişse ana rutin içinde overflow flag clear ise dallan diyen komutu overflow flag set ise dallan komutuna çeviriyor.
Geldik işin son kısmına,
8. Bellek standart moduna alınıyor ($01 portuna $37 yazılarak), CIA ve VIC eski haline getiriliyor. Yüklenen programın basic programı mı yoksa makine dilinde yazılmış bir program olup olmadığı kontrol edilip buna göre çalıştırılıyor.
Fail safe olanın videosu burada, ikincisi çok uğraştırırsa, dönüp de bulamazsam diye bunun videosunu çektim
Tabii sonrasında hızlı (kime göre, neye göre
) olan versiyonu da çalıştırdım. Şu an için saniyede 2k gibi bir transfer performansı var. Videodakinde 42 saniye süren yaklaşık 10k'lık bir yükleme hızlı olan versiyonda 5 saniyeye iniyor. 2 saniye de reset yapılırken harcanıyor.
Hardware basit, ekte verdiğim dosya içinde tüm bilgiler mevcut. Özay'dan gelecek switch'li kartuşa elinizde herhangi bir arduino türevi board varsa uygulamanız mümkün. Sd modülü bağlayıp çakalca sd kart içeriğinden seçilen dosya bilgisini arduino'ya geri gönderebilirsem kullanılabilir bir ürüne dönüşebilir. Hız açısından tercih eder misiniz merak ediyorum. (Bu hakikaten bir sorudur)
Çakalca dediğim anda aklıma bir fikir geldi bu arada
Arduino IRQ ve NMI üretebildiği gibi, bunlara bağlı io pin'lerini okuma moduna alıp dinleyebilir. 6510 tarafında çalışan kodun yapması gereken belirli bir pattern'de NMI ve / veya IRQ üretmek.
Herkese iyi bayramlar,
ps: Ekteki c64 assembly dosyalarını derleyebilmek için 64tass turbo assembler'a ihtiyacınız var. Ben geliştirmemi ve debug'ımı 6502 macroassembler & simulator programında yapıyorum. Son derleme işinde de 64tass'ı kullanıyorum.