KASET TURBOLARI
Retro bilgisayarBurada verilen program dökümü bilgisayarınızdaki ile aynı olmayabilir. Dizgi hataları olabileceğinden, siz monitör programıyla incelediğiniz döküme göre fikir yürütünüz.
Uzun zamandır dataset kullanan C-64 sahibi arkadaşlar kendileriyle ilgilenmediğimizi söylüyorlardı. Biz de bu şikayetleri göz önüne alarak, her kaset kullanıcısının hoşuna gidecek, bu arada programcıların ise sevinçten tavana çıkmasını sağlayacak bir program çeşidi bulduk. Bu yazıda, bir kaset turbosunun ne olduğunu, niye ve nasıl daha hızlı yükleme yaptığını, kasede çekilen programların nasıl korunduğunu sistematik olarak öğreneceğiz. Fakat yazının en önemli kısmı, MDE çıktısını Program Döküm Eki'nde bulabileceğiniz açık ekranla yükleme yapabilen IRO Turbo. Adından da anlaşılacağı gibi bu turbo, yükleme yaparken IRQ interruptları kullanıyor ve bir yandan da sizin programınızın çalışmasına fırsat tanıyor. Bu turbo, ekranı kapatmadan yükleme yapabildiği için bir grafik gösterebilir, yükleme yaparken bir programın çalışmasına izin verdiği için de bu grafiğe eşlik edecek bir müzik çaldırabilirsiniz. Tabi ki sadece müzikle yetinmeyenler ekranın altına bir kayan yazı ekleyebilir veya değişik programlar yardımıyla yüklemeyi daha zevkli hale getirebilir. Elinizin altında böyle bir turbo bulunduktan sonra, yapabilecekleriniz yalnızca kendinizle sınırlı kalacaktır. Aslında kaset turbolarının yaratılması, C-64'ün kaset rutinlerinin güvenliğe fazla önem vermesi, bu sebeple de çok yavaş program yüklemesi yüzünden olmuş. Daha hızlı yükleme yapabilen bir disk ünitesi almak çoğu kişinin bütçesini aştığı için, iyi programcılar, kaset yüklemesini yaklaşık 10 kat hızlandırmışlar ve neredeyse bir disk ünitesinin yükleme hızına eşit hale getirmişler. Genel olarak bir bilgisayar satıcısından aldığınız oyunlar normal olarak kaydedilmezler kasetlere. Hiç kimse saatlerce program yüklemek istemez çünkü. Onun yerine, herkes en çok hoşuna giden turboyu kullanır. Bu turboların bazıları aşırı hızlı, bazıları çok iyi korunmuş, bazıları da hızdan fedakarlık ederek göze ve kulağa hitap ederek yükleme olayını zevkli bir hale getirir. Dergimizin beş yıl önce çıkan ilk sayısında da ESRA TURBO adıyla oldukça hızlı bir turbo programı yayınlamıştık. Daha sonra ortaya çıkan turbolardan bazıları, hemen herkes tarafından bilinir: LOCKY JR I-II. Gördüğünüz gibi
bu turboların nasıl çalıştığını öğrenen herkes bir turbo yapmış. İyi de nasıl oluyor da bu turbolar program yükleme hızını değiştiriyor? Oldukça basit bir mantığı var aslında. Yalnızca bilgisayar kendi rutinleriyle kısa bir programcık yükledikten sonra -ki biz bu programcığa LOADER (yükleyici) diyoruz- bu programcık bilgisayar kontrolünü üzerine alır ve kasede daha değişik bir şekilde yazılan sinyalleri okur. Tabii ki bu sinyaller normal kayıt sırasında yazılan sinyallerden kat kat kısadır (Frekansları çok daha yüksektir).
Bir hızlı yükleyici yaratmak için iki programa ihtiyacınız vardır: Birincisi, demin de bahsettiğim, programların en başında yükleyip otomatik olarak çalışan ve bilgisayarın kontrolünü ele alan LOADER programı (bu program çabuk yüklenebilmesi için çok kısa olmak zorundadır), ikincisi ise bu loader'ı normal olarak kaydettikten sonra asıl programı hızlandırılmış sinyallerle kaydedecek olan FAST SAVE ya da HIZLI KAYDEDİCİ programdır. Bir turbo dizaynı sırasında başa çıkarılması gereken ilk problem, bitlerin kaset bantına nasıl yerleşecekleridir. Bant yüzeyindeki her bit, Şekil 1'de de görebileceğiniz şekilde yükselip alçalan bir dalga olarak yer alır. Dalganın iki ucu arasındaki uzaklık bize bu dalganın 0 mı yoksa 1 mi olduğunu açıklar. Uzun bir dalga 1'i, kısaları ise 0'ı temsil eder. (Bu tamamen size kalmış bir karardır. Canınız isterse kısaların 1'i, uzunların ise 0'ı temsil etmesini sağlayabilirsiniz.) Dalganın aşağı inen kısmında, interrupt registerlerinden birinin değeri değiştirilir ve siz de bu değerinden ve interrupt timer'larından (zamanlayıcılarından) aldığınız bilgisayara göre bu bitin değerini anlayabilirsiniz. Yükleyici, genelde interruptları kapatarak çalışan bir makine dili programıdır. İlk olarak CIA1 timer'larına gereken değeri verir ve onları çalıştırır. Bu zamanlayıcılar 0'landığı zaman da teypten sinyal gelmiş olup olmadığına bakar. Eğer zamanlayıcı 0'lanmadan önce bir teyp sinyali fark edilmişse, bu bitin değeri 0 olur. Aksi takdirde değer 1'dir. Daha sonra bu bitler bir bayta alınır ve 8 bit okunduktan sonra bellekte gereken yere yazılırlar. Tabii ki demin bahsettiğim normal hızın yükleme programları için geçerli olan mantıktır. Bizim loader'imiz ise daha değişik bir şekilde çalışır. İlk olarak bunda da timer'lar ayarlanır. Fakat teypten sinyal alınınca (dalganın aşağı inen kısmına gelinince) bir interrupt yaratılır. Bu interrupt'a girer girmez timerların değeri okunur ve yeniden çalıştırılır. Eğer okunan değer 0'dan farklıysa, kısa bir sinyal okunmuş demektir, yani bitin değeri 0'dır. Fakat asıl program, baytların okunmasından önce loader'ı sinyallerle senkronizasyona sokmaktır. Yani gelen bitin tam yerini saptamasını sağlamaktır. Bunu yapmak için, her baytta yalnızca bir bitin değeri 1 olan bir seri sıfır yazılır teybe. Loader rutini daha sonra bu bitin doğru yere gelmesini sağlamaya çalışarak kendini yazılı bitlere uydurur. Daha sonra güvenlik için yazılan bir baytlık bir değer de olması gerekenle aynı olarak saptanırsa, yüklemeye geçilir. Eğer bu baytın değeri tutmazsa, veya bitin yeri ayarlanamazsa, rutinin başına dönülür ve senkronize etme çalışmaları sürdürülür. Dergide yayınlanan ESRA TURBO ise bu konuda değişik bir yöntem uyguluyordu. Baştaki bir seri baytın değeri ayarlandıktan sonra dokuzdan sıfıra kadar olan tüm baytların orada bulunup bulunmadığı kontrol ediliyordu. Bu sayede ekstra güvenilirlik sağlanmıştı. Siz de kendi turbolarınızda güvenlik sağlamak için veya standartlara aykırılık olsun diye değişik bir giriş yapabilirsiniz. Demin bahsettiğim senkronizasyon baytının değeri 0/9 01000000 — $4A — 64 olabilir mesela (bizim turbomuzda da bu değer veriliyor). Bu değer birkaç kere ard arda (bizde 64 defa) yazılarak turbonun kendini bu bayta adapte etmesi sağlanır. Bu bayt ve güvenlik baytının değerleri olması gerekenle aynı olduğu zaman rahatlıkla programın datalarını yüklemeye girişebiliriz. Programın nasıl kaydedileceği tamamen size kalmıştır. Bizde, ilk olarak başlangıç ve bitiş adreslerini belirten dört bayt yazılır ve bu baytlardan alınan bilgiye dayanarak yükleme yapılır. Daha sonra, kaydedici rutin tarafından hesaplanan kontrol toplamı baytı alınır. Yükleme sırasında da yapılan kontrol toplamı baytıyla bu bayt karşılaştırılır. Eğer ikisi de aynıysa, yükleme başarıyla gerçekleşmiş demektir. Farklılarsa, istediğiniz şekilde yükleme hatası bildirebilirsiniz. Programın kaydedilmesi sırasında çok değişik bilgiler kaydedebilirsiniz. Mesela NOVALOAD'ların yaptığı gibi her parçanın ismi başa yazılabilir veya güvenlik için bir anahtar kelime sistemi kurup yüklenen kelimeyle verilenin aynı olup olmadığını karşılaştırabilirsiniz. İsterseniz programı sondan başa yükleyebilirsiniz veya belirlediğiniz bir düzenle yükleme yapabilirsiniz. Yani bir kere senkronizasyon baytını bulup da güvenlik baytıyla aynı değeri okuduysanız, yapacaklarınız tamamen sizin hayal gücünüze kalıyor. Teoride her şey çok kolay geliyor değil mi? Peki nasıl olacak da her şeyin çalışır hale gelmesini sağlayacağız? Aslında bu iş pek de zor değildir. C-64'ün ekran açıkken fark edebileceği sinyal uzunluğu herhangi bir formülle değil, deneme-yanılma metoduyla bulunmuştur. Elimizde bulunan tek şey, kısa olan dalganın boyunun uzun olan dalga boyunun yarısından biraz fazla olması gerektiğidir. Teyp donanımı sayesinde bu ufak fark hemen hemen sıfıra iner. Programımız 49152 adresinde yer alıyor ve SYS 49152 komutuyla aktif hale geçiyor. Turbo formatında kayıt yapabilmek için SAVE “isim”, 7 komutuyla kayıt yapmanız gereklidir. Yani 7. üniteyi hızlı teyp olarak tanımlıyor programımız. Hızları karşılaştırabilmeniz için 26,3K'lık bir BASIC programı değişik şekillerde kaydettik ve yükleme sürelerini ölçtük, hangisini kullanacağınıza siz karar verin:
Disk 1: 1 dakika 10 saniye TURBOLU: 1 dakika 25 saniye Turbosuz: 8 dakika 40 saniye
Eh artık gelenekleşmiş şekilde programın açıklamasına girişebiliriz:
Lda # < Savevec
Sta $0332
Lda — # >Savevec
Rts
Bu komutlarla SAVE komutu işleme sokulmadan önce bizim rutinimize sıçrama yapılmasını sağlıyoruz.
Savevec Pha
Lda $BA
Cmp — #507
Beg Tsave
Pla
Jmp —$FSED
Eğer ünite no'su ($B5'de tutulur) 7 değilse normal SAVE işlemine geçmesi sağlanır.
Tsave Ldy — # $8E
Lda # $20
Loop | Sta Flnamet 4 1,Y
Dey
Bne Loop İ
dosya adı temizleniyor.
Birinci üniteye kayıt yapılacağı ve dosyanın detayları bilgisayara bildiriliyor.
Ldy $B7
#$0F Lda # $BB
Bec Loop 2 Ldx #< Flname
Ldy $OE Ldy # > Flname
Loor 2 Dey IJsr $FFBD
Bmı Tsavel
Lda ($BB),Y Burada ufak bir bile kullanılıyor. Yani programın adiy-
Sta Flname 4 2,Y la birlikte uzunca bir de program parçası ($BB bayt) kay-
Jmp — Loop2 dediliyor kasede,
Bu kadar satır yalnızca $B7 adresinden dosya adı uzun- Lda # $80
luğunu alıp. $BB'nin gösterdiği adreste bulunan dosya Sta $9D
ismini gereken adrese taşımaya yarıyor. Lda # $02 ; Kayıt başlan-
Tsavel Ldy — # $50 Sta
Tsave 2 Lda — Loader,Y Lda ;
Sta $O2AB,Y Sta $EB ;
Dey Ldx ; Bitiş
Bpl - Tsave 2 Ldy ; adres
İsr $FFDO
Hızlı yükleyicinin (LOADER) bir parçası gerekli yere
taşınıyor. Loader kısmı kasede normal ve Autostart olarak kay-
dediliyor.
Lda #$01
Tax Lda — #$03
Tay Sta $0302
Jsr $FEFBA Lda #$A4
Sta $0303
Lda
Sta $9D
Ldx — #$00
Ldy # $00
Autostart yapmak için bozduğumuz değerleri normale çeviriyoruz.
Seveil Jsr WrtHdr
İlk olarak senkronizasyon ve güvenlik baytlarını yaz.
Lda — $2B
PHa
İsr WrtByt
Lda — $2C
Pha
Jsr WrtByt
Lda — $2D
Jsr WrtByt
Lda — $2E
Jsr WrtByt
Değeriyle oynanacak değişkenleri stack'e atarken, başlangıç ve bitiş adreslerini kasede yaz. Sty $FB
Kontrol toplamını sıfırla
Ldy $2B.
Lda # $00
Sta $2B
Tsavloop Lda ($2B),Y
Jrs WrtByt
Iny
Bne Tsave 3
Inc SAÇ
Tsave 3 $2D
Lda $2C
Sbe $2E
Bec Tsavloop
Programın tamamının kaydedilmesi burada yapılıyor.
Lda $FB
İsr WrtByt
WirtByt
Kontrol toplamını da yazalım ve son biti de kapatalım.
Lda —#$1B
Sta $D811
Lda —#$37
Sta $01
Ch
Pla
Sta $2C
Pla
Sta $2B
Jsr $FF84 ; V/D'u toparla
Jmp SA474
bozduğumuz her şeyi toparlayıp, teybi durdurup BASIC'e dönüyoruz.
WrtHdr Lda # $06 ; Basic ROM'u
kaldır
Sta $01 ; ve teybi çalış-
tır
Lda #$0B ; ekranı kapat
sta
Headri Dex ; Teyp tam
Bne Headrl ; hızına
Dey ; ulaşana kadar
Sel
Lda ; Bekleme için
Sta $DDO4 ; başlangıç
Lda #$0A ; timer
Sta $DDOS ; değerleri
Lda #$19
Sta $DDOE ; Timer'i başlat
Buraya kadar teype yazabilmek için gerekli olan adreslerin değerlerini ayarladık.
Ldy #$40 ; Tekrar sayısı
Headr2 Lda ; Senkronizas-
yonbaytı
İsr WrtByt ;01000000'u yaz
Dey
Bne Headr 2
teybe 64 defa $40 yaz.
Lda
İsr
#$SA
HrtByt
; Güvenlik baytı
Güvenlik baytını unutma.
WriByt Sta
Eor
Sta
Lda
Sta
Rol
İsr
Deo
Bne
Rts
Wbyte |
$BD ; baytı sakla
$EB ; kontro! tepla-
mini
: hesapla ve
sakla
# $00 ; yazılacak bit
sayısı
$A3
$BD
WrtBit
SA3
Whytel
Teybe bir bayt yazmanın yolu budur işte.
WrtBit Lda
Ldx
Stx
Lda
Lta
Bit
Wbit 1
Wbit
Beg
Lda
Bor
Sta
Inc
Lda
Sta
Lda
Bit
Beg
Lda
EOR -
Sta
Lda
Sta
Rts
Wbit 2
#$70 ; bit değeri O
kabul et
Wbit 1 ; gerçekten de 0
# $FF ; değer 1'miş
$DD84 ; Timer'ı ayarla
$DDO5S
#$01
$DDOD ; Timer'ın bit- 2
mesini
Wbit 2 ; bekle
$01 ; teybe yazılan
# $08 ; voltajı ters
$01 ; çevir
$DO20 ; Çalıştığını gös-
ter
#S$DI9 ; Timer'ı gene
$DDOE ; çalıştır
#$01
$DDOD
3
$01
# $00
$01
#$19
$DDOE
İşte teybe kayıt yapmanın can alıcı kısmı. Eğer yazılacak olan bit 1 ise $FF'den, 0 ise $70'den geriye sayıyoruz (iki kere) ve her sıfırlanışta teybe yollanan voltajın yönünü değiştiriyoruz. Bu sayede değişik boylarda dalgalar yaratabiliyoruz. Rutini terk etmeden hemen önce Timer'ı tekrar çalıştırıyoruz ki arada beklemeden dolayı zaman kaybımız olmasın. Loader de buradan başlıyor. Size önerim, $C13F'de bulunan bu programı incelemeden önce $02AB'ye taşımanızdır, çünkü bu program orada çalışmak üzere tasarlanmış:
Ldy
Lda
Sta
Loader
Biloop
Dey
Sel
Lda
# $05
# $02
$0450,Y ; Ekranda artan
READY'ı
; siliyoruz
Biloop
$01 ; teyp de çalış-
Sta
Lda
Sta
Sta
Lda
Lda
Lda
Sta
LDa
Sta
Lda
Sta
Lda
Sta
Lda
Sta
Lda
Sta
Lda
Sta
Lda
Sta
Cli
Jmp
$01 ; teyp de çalış-
sın
#$1F ; oluşacak inter-
rupt türü
$DCOD
$DDOD
$DDCOD ; Bu registerleri
okuyarak
$DDOD ; aktif hale ge-
tiriyoruz
# $68 ;
$DCO4 ; Timer'ları
# ; ayarla
$DCOS ;
# $90 ; Tape IRO'nun
$DCOD ; aktif hale getir
$FFFE ; IRO başlangıç
; adresi
#$7B
$FEFFA ; NMI'ı Bir BTI
# $03 ; gösterecek şe-
kilde
$FFFB ; ayarla
$00 ; sinyali
$02 ; sıfırla
$03DD
Yüklemeye giriş için gerekli tüm adresler ayarlandı.
02F3 Lda
Sta
Lda
Sta
Lmp
0300 word
# $03
$0302
# S$A4
$0303
$FF84
$E300,$02AB ; autostart adre-
si
Burası sadece yüklemenin sonunda gelinen etrafı toparlama rutini.
Flame
0351
$0364
— “*isim
Pha
Tya
Pha
Lda $DCOS
Lday #$19
Sty $DCO3
Eor # $02
Lsr
Lsr
Rol
Lda — $A9
Becc Hitgot
Bes Exit
;Kullanılacak
; registerleri
; Stack'e at
; Timer'ı al
; Timer'ı yeni-
den
; başlat
; Bit'in değerini
; CARRY'ye al
; Bayt'ı bayta al
; Bayt'ı al
; bayt tamam-
landı
bayt tamamlan-
madı
Interrupt'ın girişinde, bit'i alıp, gerekli bayta ekliyoruz. Bayt tamamlanmadıysa, interrupt'tan çıkıyoruz. Tamamlandıysa:
Bitgot
Cmp #
Bne Exit
Lda #$16
Sta $0365
; Senkronizas-
yon?
; hayır
; evet
; rutin 1'i göster
Burada oldukça etkili bir hile kullanılmış. $0364'teki Bcc'nin ikinci baytının değeriyle oynanarak, teypten bayt okunduğunda yapılan işlemler değiştiriliyor.
Ex 1
Exit
Lda — #$FE
Sta $A9
Lda $DCOD
Pla
Tay
Pla
Rti
; Gelecek baytın
bitişini
; anlamak için
; İnterrupt'ı te-
mizle
Ve interrupt'ı terk edip asıl programa dönüyoruz.
rutin | Cmp
Beg
Cmp
Beg
Lda
Lda
Bne
Bitgt 2 Lda
Sta
Lda
Sta
Beg
# $40
Ex |
# $SA
Bitgt 3
# $02
$0365
Ex İ
# $30
$0365
# $00
$CI
Ex1
; hâlâ senk. baytı mı? ; evet, öyleyse bekle ; güvenlik baytı? ; hayır, öyleyse senk. ; baytı aramaya devam.
; Rutin 3'ü göster
; kontrol toplamını ; sıfırla ; interrupt'tan çık
Burada da güvenlik baytı aranıyor. Eğer bayt ne senk. baytı ne de güvenlik baytıysa senkronizasyon yapılmamış demektir, başa dönüyoruz. Güvenlik baytıysa rutin
3'e geliyoruz. Rutin 3 Sta
Inc
Lda
Cmp
Bne
Lda
Sta
Bne
Rutin 4 Ldy
Sta
Eor
Sta
Sta
Inc
Inc
Bne
Inc
Bitgt 5 Lda
Cmp
Lda
SBC
Becc
Lda
Sta
Bne
Rutin 5 Sta
Lda
Sta
Lda
$FB
Rutin 341
Rutin 34 1
$FF
Exi
# $43
$0365
Exİ
# $00
($FB),Y
$C1
$CI
$CI
$DO20
$FB
Bitgt 5
$FC
$FB
$FD
$FC
$FE
Ex 1
# $65
$0365
$C2
# $FF
$02
# $03
; Başlangıç, bitişi al. ; adresi bir artır ; $FB, $FC, $FD, $FE'ye ; değer yaz
; dört bayt da alınınca ; rutin 4'e geç
; baytı belleğe yaz ; kontrol toplamı ; kontrol toplamı ; hesapla ; çalıştığını göster
; yüklemenin sonuna ; geldik mi? : HAYIR! ; Rutin 5'e geldik
; kontrol toplamı oku ; Bitiş sinyali ; ver! ; Gene Bitgot'a
Sta $0365 ; Çevir
Lda ; Bir daha kul-
lanılâbilir
Sta Rutin 341 ; hale gelir
Bne Exl
Yükleme kısmı bu kadarıyla ilgileniyor. Bu arada bütün yükleme boyunca çalışan bir de programımız vardı:
; Sinyal geldi
mi?
; HAYIR! bek-
le.
$03DD Lda $02
Beg $03DD
İlk seferde bir şey yapmak istemediğimiz için normal
program olarak hiçbir şey koymadık. Yalnızca yüklemenin bilinmesini bekliyoruz.
Lda $00
Sta $01 ; sinyali temizle
Ldoa # $07 ; ROM'lar içeri
Sta $01
$03F3 ; Etrafı toparla!
İsr $A663 ; CRL komutu
Lda $CI ; kontrol top-
lamarını
Cmp $C2 ; karşılaştır
Bne ERROR ; FARKLI!!!
Jmp — A474 ; 'REDY.' yaz
ERROR Ldx # $1D ; ?LOAD
EROR'
İmp — $A437 ; Mesajı yolla
Fark ettiğiniz gibi rutin AUTORUN için ayarlanmamış. Fakat bu işi yapmak çok kolay.
Jmp — $SA474
# yerine
İsr $A659
Jmp —$A7AE
yazın. Dosya adı uzunluğunu üç artırın. Programınız artık AUTORUN da yapacaktır. $A7AE adresinde RUN komutu bulunmaktadır çünkü.