BİLGİSAYARLI GERÇEK ZAMAN SAATİ HARDWARE

aktif-high olan devreleri sürebilmek için ayrıca bir invertör gerektirir.

Şekil 2 Adres Decoder

16 15 13 12 do ş

D 74139

-TDDR5260: Dual 7-Segment Display

TDDR5260, ekranında sayıyı oluşturmak için 7-segment ve 1 nokta kırmızı LED(Light Emitted Diode)'lerinden oluşmuş ortak katodlu bir elemandır.

Şekil 3

TDDR 5260 -Dual-7-Segment Display

D18 17 16 15 14 13 12 11 10 a1 a2

h Vb

1 2 e/ 3 fa ez/ fc di d2 Oppi O pp2

1 2 3 4 5 6 7 8 9 l-el 10 b2 2-di İl a2 3-c1 12 f2 4-DP1 13 A2(K2) 14 Aİ(KI) 6-d2 15 bi 7-2 16 al

17 gl 9-DP2 18 fI

-R1...R7: 56-100 Ohm arasında seçilebilen dirençler.

-Rd : 220-270 Ohm arasında noktaya ilişkin direnç.

-LED ışığının düzgün görülebilmesi için şeffaf kırmızı pleksiglas parça.

-User Port konnektörü.

Saatin Çalışması:

Devrenin temel prensibini anodu bir veri çıkışına, katodu ise bir kontrol çıkışına bağlanmış bir LED üzerinde açıklamaya başlayabiliriz. Bir kırmızı LED yanıyorsa anod-katod arasında 1,6 V gerilim vardır. Ki bu LED'in doyuma ulaştığında elde edilen gerilimdir. Kontrol ucunu toprağa bağlayıp veri ucunu ise bir veri çıkışına bağlarsak, lojik verinin değerini burada görebiliriz. Veri lojik 1 ise LED yanar, lojik 0 ise LED sönük kalır (Şekil 4).

Şekil 4

R veri O— ME

KONTROL 0

Bundan sonraki adımda kontrol ucunu toprağa değil de bir kontrol çıkışına bağladığımızda çeşitli durumlara ilişkin Şekil 5'teki tablo oluşur.

L: Low seviye H: High seviye

H H

Şekil 5

Tablodan görüldüğü gibi LED, kontrol girişi lojik 1 ise devre dışı bırakılmıştır (veri ne olursa olsun LED sönük). Çünkü hiçbir zaman anod-katod arasında yeterli pozitif gerilim oluşamaz. Ya negatif bir gerilim vardır ya da iki uca da lojik 1 uygulandığından iki uç arasında gerilim farkı yoktur (0V). Kontrol girişine lojik 0 değeri verilmiş ise bu durumda veri doğrudan ışık olarak görünür. Veri lojik 1 ise LED yanar vs. Prensipte bir adım daha ilerleyelim: 4 adet LED'imiz var ve bunların anodlarını sadece bir veri yoluna bağladığımızı ve katodlarını ise 74139'un aynı mantıkla çıkış veren bir adres çözücü benzeri elemanın çıkışlarına bağladığımızı düşünelim. (Şekil) 6 Şimdi biz bir veri ve iki bitlik bir binary sayı veriyoruz. IC1 verilen binary sayının değerine göre sadece o numaralı çıkışı 0 yapıyor ve diğerlerini ise lojik 1'de bırakıyor (Şekil 7). Bu durumda ne olur? Herhalde bu sorunun yanıtını tahmin edebiliyorsunuz: Sadece katod'u low konuma çekilen LED'de veri görünecektir. Kontrol 0 = L, Kontrol 1 = H, veri = H'de sadece Q2 L değerinde olacak ve veri de H olduğundan LED2 yanacaktır. Peki ama biz ne görmek istiyoruz; sadece bir LED'in yandığını mı? Hayır; buradaki esas amaç aynı anda 4 LED'de de farklı veriler görmek istiyoruz. Elimdeki böyle bir düzenekten, nasıl dördü birden çalışan duruma gelirim? Sinemanın çalışma prensibini bilirsiniz, insanın göz kusuru, yani gözün saniyede belli sayıdan fazla değişikliği algılayamaması, dolayısıyla birbirinden ayrı resimlerin, gözün bu özelliği sayesinde hareketli şekiller olarak algılanması.

Aynı şekilde bir lambayı çok hızlı ve

devamlı bir şekilde yakıp söndürürsem lamba, gözün belli bir hızdan sonrasını fark edememesi dolayısıyla, gözün sadece ışığı algılayabilmesi sonucunda devamlı yanıyor görünür. Dolayısıyla bir grup LED'i sırayla tek bir hattan devamlı olarak sabit değerlerle yükleyerek tararsak, belli bir hıza kadar LED'lerin sırayla değer al-

Kontrol 0

MU Kontrol 1 dığı seçilebilir, ama sonra LED'ler sanki sabit değerlerde kalıyormuş gibi görünürler. Bu sayede fazla veri hattı kullanmadan çok miktarda LED'e sabit değerler yüklenmiş olurum. Artık 4 LED'in bir veri yolu üzerinden nasıl yakıldığını görmüş olduk bundan sonraki aşama ise çok sayıda 7-segment display'in yakılmasıdır. Bu ise devrenin gene çok az veri ve kontrol ucu istemesi için Şekil 8'de görüldüğü gibi bir 74139 ve 4543 çifti sinemada göz resimler hızlı bir süreklilikle hareketli şekiller gibi görünür.

ile yapılabilir. 4543 display'de görünecek sayıya ilişkin BCD değeri alır ve 7-segment'e kod çevirir. 74139 ise o anda hangi display'den verilerin görüneceğini saptar. Bu durumda herhangi bir konumda dururken sadece adres decoder'in seçtiği display'de girişte verilen BCD sayı görünür. 4 ayrı LED'de yapılan tarama işlemini çok hızlı bir şekilde her display'e ayrı değerler gelecek şekilde gerçeklersem, 4 display de sabit yanıyormuş gibi görünür. Böylece normalde 4 display'e çeşitli değerler yazmak için 4x8=32 veri hattı gerekirken

H Şekil 7 | ben bu işi 4 BCD sayı için, 2 adres decoder için ve 1 de nokta için olmak üzere 7 hat ile gerçeklemekteyim. Burada hat kazancı görüldüğü gibi çok büyüktür. Peki niye her display'in girişine, girişleri veri yoluyla bağlanmış ve bir 74139 ile kontrol edilen 8 bit latch (saklayıcı)'lar bağlanamadı diye soracak olursanız biraz düşünmekle sizin de anlayabileceğiniz gibi i) 4 ayrı latch'den dolayı masraf artacak ii) yine bu fazla elemanlardan dolayı baskılı devreyi hazırlamak çok zorlaşacak, iii) baskılı devrenin boyutu büyüyecek şeklinden pek çok sorunla karşılaşacaktınız. Şemada bulunmayıp baskılı devre şemasında bulunan C1 ve C2 kondansatörleri 0,1 µF değerinde seramik olup, entegrelerin girişinde meydana gelebilecek gerilim değişimlerini kompanze etmek için konulmuştur.

Gerçeklenmesi:

Devrenin çalışma prensibini gördükten sonra artık bunun nasıl bilgisayar tarafından çalıştırılacağını anlatmaya başlayabiliriz. Devre için gerekli olan 7-bit'lik bilgiler portta çıkışı bulunan CIA 2'nin B portundan alınsın. Tabii ki, toprak ve gerilim uçları yine user port'un ilgili pinlerinden alınacaktır. Bu konuda size tavsiyem devreyi, baskılı devre plaketi üzerinde gerçeklemenizdir. Yok-

sa kablo karmaşası arasında kalabilirsiniz! Software: 6526 CIA chip'ini bir iletişim birimi olarak kullanmaya başlamadan önce chip'in port'una ilişkin bitlerin giriş mi, yoksa çıkış mı olacağını bilgisayara anlatılması gereklidir. Bu da giriş bit'leri 0, çıkış bit'leri 1 olarak aldığımızda meydana gelen sayıyı, port'un veri yön register'ine yüklemekle olmaktadır. B portuna ilişkin veri yön register'i 56579 = $DD03 adresinde, ve veri portu ise 56577 = $DD01 adresindedir. PB0 ve PB1'den çıkış, PB2'den de giriş olmak istediğimizde $DD03 adresine 3 değeri (00000011) yüklemek yeterli olacaktır. Kullanılmayan bitlerin yönü önemli değildir, keyfi değer alabilirler. Çıkış olarak LED'leri düşünürsek Şekil 11'deki gibi bir bağlantı yeterli olur.

Şekil 11

Burada dirençler LED'den geçen akımı sınırlamak için kullanılmıştır. Bu bitlere verdiğimiz değerlere göre LED'ler yanarlar. Aynı şekilde giriş olarak da bir anahtarı düşünürsek Şekil 12'deki deneyi kullanabiliriz. R3 pull-up direnci olup, anahtar açıkken PB2 = 5V, kapalı iken 0V olması bu direnç sayesindedir.

Şekil 12

*5v

PB>

Anahtarın ne konumda olduğunu bir peek komutu ile öğrenebiliriz. Son olarak anahtar açıkken LEDİ'i yakan, aksi durumda LED?'yi yakan bir program yapalım:

10 POKE 56579,3
20 A—56577
30 C- (PEEK(A)AND4)
401FC- 0THENPOKEA,
GOTO 30 ;
50 POKE A, 0: GOTO 30

Saat Programı: Bilgisayarı sadece bir saati işletmek için kullanmak herhalde pek pahalı bir saate sahip olmak dışında hiçbir anlam taşımaz. Bu nedenle yazılmış olan saat programı interrupt ile sürülmekte ve bu sayedeizin bilgisa- .

yarla uğraşmanızı kesmeden saniyede belirli bir sayıda çalıştırılmaktadır. Program her seferinde bir önceki sefer yanık bıraktığı display'den bir sonrakine geçmeke ve ona değer yükleyip yakmaktadır. Dolayısıyla tüm display'lerin taranması için programın 4 defa interrupt ile çağrılması gerekmektedir. Bu noktada bir soru sormak isteyebilirsiniz: Niye her interrupt'ta sadece bir LED'i yanık bırakıyorsunuz da, tüm LED'leri sırayla yakmak gibi bir yola gitmiyorsunuz? Bunun nedenini de basitçe şöyle izah edebilirim:

Bir LED'in aktif olup doymaya ulaşıp ışık vermeye başlayabilmesi için belirli bir süre gerekmektedir . Aksi halde machine-code hızında yapılan böyle bir tarama sonucunda, LED'lerin aktif olması için gerekli zaman olmadığından dolayı ışık vermezler.

Programda CIA | saat olarak programlanmıştır. Display'lere yazılacak veriler ise CIA 1'ingün zamanı saatine (GZS) ilişkin adreslerden okunarak bulunmaktadır. CIA 1'in GZS'nin adres ve anlamları aşağıdadır:

1/10 Saniye : 56328 $DC08

Saniye : 56329 $DCO9 Dakika : 56330 $DCOA Saat AM/PM : 56331 $DCOB

Program konusunda son olarak şu da bilinmelidir: Commodore'da normalde saniyede 50 kere interrupt oluşmaktadır. Bu da saat programının saniyede 50 kere çağrılması sonucunu oluşturur. Yani saniyede 56/4 — 12,5 kere bütün display'ler taranmaktadır. Bu, bizim göz hassasiyetimiz sınırında olduğu için LED'- ler eğer bu şekilde çalıştırılırsa sabit duruyor görünmezler. Devamlı titreşirler. Bunu engelleyebilmeki çin makinenin saniyedeki interrupt sayısı arttırılmıştır. Bu durumda gerçi cursor çok hızlı yanıp sönmekte, space

TDDR 5260

01234567 6ND

4...

ve sağ, sol vs. gibi bazı tuşlarda çok hızlı hareket sağlamaktadırlar. Bu belki size başta antipatik gelebilir, ama görüntü çok nettir ve bunlar sorun oluşturmaz. Programın 20. satırındaki AD değerine çeşitli değerler vererek, çeşitli adres bölgelerinde program çalıştırılabilir. Teyp kullanmıyorsanız teyp giriş/çıkış buffer'ı (828-1019 — $033C- $03FF) sizin için ideal yer olabilir. Eğer teyp kullanıyorsanız yine (49152-53247 — $C000-$CFFF) serbest 4096 byte ram alanı iyidir. Saati herhangi bir anda değiştirmek isterseniz ilk önce saat ve en son saniye/10 olmak üzere verileri poke etmeniz yeterlidir. Artık siz program yazarken veya Basıc vs. gibi bu interrupt yapısını bozmayan programları kullanırken zamanı doğrudan kontrol altına alabileceksiniz! Deneyeceklere başarılar dilerim...

SAAT PROGRAMI
1 EÇM KA EKA RA kak 310 POKE ADtA4,AL:POKE
2 * * 315 POKE
a SEM $ COMMODORE DERGİSİ * 3206 PÜOKE AD*20,CL:POKE
4 REM * 19387 * 325 POKE AD*34 ,CL:PORE AD4*35,CH
— PEM * * 330 POKE
REM # ok e de kok öle ole ole Ole kk 335 POKE AD*4*5İ,CH
7 LUTFEN BIRAZ BEKLEYİN." 340 POKE AD*75,AL:POKE AD4*76,AH
18 DEFFN 2345 POKE
28 AD-828 350 POKE
20 FOR Tü H$ 400 SYS
40 405
m2 410 INPUT
BA POKE 420 INPUT
TA NEXT 430 INPUT
120 440 T-56328
1152 450 POKE Lİ<H)
120 468 T*2,FN W<D)
130 478 POKE WS)
140 488 POKE
150 430 INPUT "SAAT SEKLİ.:";S
160 500 POKE
172 518 END
180 REM kiki kalk kk dek ele ok deo OK dek
130 605 REM * AD4*33 : SAATI AKTIF YAPMA *
6lü REM * SARTIN SEKLİ *
212 ,DC 615 REM *« 56331 : SAAT *
620 REM * 56330 : DAKIKA *
230 625 REM * 563293 : SANIYE > *
240 630 REM * 56328 SANIYE/ZİR *
250 DATASÖ,EA 635 REM kk le dek eke ole Me Ok ak ok
280
301 BAZADtI
302 READY.

Merhaba arkadaşlar... Bu bölümümüzde önce geçmiş bölümlerimizde çıkan bazı baskı hatalarını giderdikten sonra, son iki bölümdür DISK-MON ile kullandığımız Track/Sector komutlarını BASIC ile nasıl kullanacağımızı göreceğiz. Önce düzeltme- Dizimizin ilk bölümünün yeraldığı 17. sayının 47. sayfasında en son çizim olan 1541'in Track Düzeni'ni dikkate almayın. Bir sonraki sayıda doğru çizim basıldı. 18. sayı temiz. Gelelim 19. sayıya... 47. sayfada orta kolonun sonlarında “Örneğin bu durumda...” diye başlayan cümle bir örnekten bahsediyor ama örnek ortalıkta yok. Bu örnek LOAD“$:B? — S”',8 olacaktı. Aynı sayıda 48. sayfadaki programın 130. satırında SYS 62957 olması lazım. 60 numaralı satırda da parantezin kapatılmasını unutmamak gerek. 19. sayı, hata yönünden biraz zengin. Aynı sayfanın sağ kolonunun başlarında bir komut listesi var. PRINT, INPUT ve GET komutlarının arkasında SHIFT-3 ile çıkan diyez (#) işaretinin olması gerekiyordu. Aynı şey, 49. sayfadaki üçüncü paragrafın ilk satırları için de geçerli. Gene 50. sayfada 3. paragrafta sözü edilen hata mesajları tablosunun bir sonraki sayıda çıktığını biliyor olmalısınız. Bu paragrafın biraz aşağısındaki dört satırlık program parçasında A$ ve CLOSE arasında noktalı virgülün yanısıra iki nokta üstüste de bulunmalıydı. Yani doğrusu ...A$;:CLOSE SE.... Son olarak da, aynı bölümün sonlarında SCRATCH ile ilgili örneklerden sonra gelen paragrafta diye geçen örnek, “S:B? — P” olmalıydı. Gelelim 20. sayıya... Daha ilk RE-NAME örneğinde RENAME ve arasında iki nokta üstüste unutulmuş. Hemen yan kolondaki örneklerden ikincisinde ise DENİ - DEN- F yerine DENIİ FF olmalıydı. COPY ile ilgili örneklerde ikinci ve dördüncüde COPY - DENİ,FF yerine COPY:A2 - DENI, FF ve C:A2—DENİI,FF gelmeliydi. 21. sayıda ise pek fazla hata yok. Ama olan da çok önemli. 54. sayfanin başlarında disket komutlarını DISKMON'da kullanabilmek için başlarına O harfi eklemek gerektiği yazılıyor. Bu © harfi değil, P ve * tuşlarının arasındaki O karakteri olmalıydı. Yazının sonlarına doğru gelen .M 00 OF komutunda F'nin solundaki karakter ise sıfır rakamı, O harfi değil...

Gelelim asıl konumuza. Disket üzerindeki program ve verileri OPEN, PRINT , INPUT , GET , SAVE, LOAD gibi komutlarla kullanırken disketin blok yapısı ile uğraşmamız gerekmiyordu. DOS, bu işi bizim için hallediyordu. Ancak, DOS'un bu yolu kapatmadığını ve bloklara direkt müdahale imkânını da verdiğini geçen iki bölümümüzde gördünüz. Ancak bunların kullanımı için DISKMON gerekiyordu. Bir oturuşta disketin üzerinde işlemler yapmak için ideal bir yardımcı olan DISKMON'u ne yazık ki BA-SIC programlarının içinden kullanamıyoruz. Örneğin bir BASIC programında disketteki bir bloku okumak istersek veya disketin üzerinde yerini kesinlikle bildiğimiz bir byte'ı değiştirmeye kalkışırsak ne olacak? Konumuz bunları olası kılacak yöntemleri öğrenmek. Disketteki bir bloka direkt girmek için 1541'in içinde bir tampon bölge-

iskete bir

bloku doğrudan yazabilmek için 1541 üzerinde bir tampona ihtiyacımız var. Buna BUFFER diyoruz.

ye (buffer) ihtiyacımız var. Bizim bloka yazacağımız bilgiler önce bu tampon bölgede toplanır ve tamamlanınca diskete yazılır. Veya disketten bir blok okunduğunda önce bu bölgeye okunur ve sonra COMMODORE 64'e gönderilir. 1541'in 0-4 arası numaralandırılmış 5 değişik buffer'ı vardır. Bunlar 1541'in içinde yeralan RAM'da bulunurlar ve 256'şar byte uzunluğa sahiptirler. Yani bir bloku tam olarak içerebilirler. Dört numaralı buffer, o anda 1541'in içindeki disketin BAM 'inin okunup saklandığı bölge olduğu için bizim kullanımımıza açık değildir. Üç numaralı buffer da, eğer o sırada OPEN ile açılmış bir dosya varsa, 1541 tarafından kullanılıyor demektir.

Bu buffer'lardan birine, birazdan anlatmaya başlayacağımız komuuları kullanmak için, ihtiyacımız var. 1541'in o anda boş olan buffer'lardan birini bize ayırması için şu komutu göndermeliyiz: OPEN #4”

Böylelikle 8 numaralı aletten (1541'den) 1 numaralı dosya olarak 2 numaralı kanala ait bir buffer istemiş olduk. Eğer aşağıdaki programı çalıştırırsanız, kaç numaralı buffer'ın bize verildiğini de görebilirsiniz:

10 OPEN 1,8,2,“*#” 20 GET 1,A$ 30 PRINT ASC(A$+CHR$(0)) Gördüğünüz gibi, GET işlemini OPEN'dan hemen sonra yapmamız gerekiyor. Eğer başka işlemlerden sonra böyle bir GET yaparsak, elde edeceğimiz cevap buffer numarası olmayabilir. Aslında istediğimiz numaralı buffer'ı da çağırabiliriz:

OPEN

Ancak bu durumda o buffer'ın daha önceden başka bir kanala gönderilmiş olması nedeniyle bize verilememesi sorunu ortaya çıkabilir. Bu nedenle, eğer böyle bir komut kullanırsanız, hemen arkasından hata kanalını okuyun. Cevap 70,NO CHANNEL,00,00 ise, istediğiniz buffer'ı alamamışsınız demektir. Eğer o anda kullanılan bir başka dosya yoksa, toplam dört adet buffer'ı kendinize ayırabilirsiniz ve bunların numaralandırılması 3-0 arasında olacaktır. Aşağıdaki program ile bunu deneyebilirsiniz:

10 OPEN 1,8,15,“1”
15 K-2
20 OPEN 2,8,2,“#”
25 GOSUB 100
30 OPEN ”
35 GOSUB 100
40 OPEN
45 GOSUB 100
50 OPEN
55 GOSUB 100
60 OPEN 6,8,6, 4”
65 GOSUB 100
70 END
100 GET #K,A$
110 PRİNT ASC(A$ 4 CHRS(0))
115
120 GET #1,A$
130 PRINT A$;
140 ITF ST < >64 THEN 120
150 RETURN

Sırasıyla 3,2,1,0 buffer'larının geldiğini ama en sonda da 70,NO CHANNEL,00,00 oluştuğunu göreceksiniz. Bu buffer'ların içerikleri GET # veya INPUT # ile okunabilir,

PRINT # ile de içlerine yeni bilgiler girilebilir. Yalnız burada bir sorun karşımıza çıkacaktır. Eğer buffer'daki bilgiyi oluşturan byte'lar arasında belli aralıklarla virgül, iki nokta üst üste, RETURN kodu (13) gibi byte'lar yoksa INPUT # sorun çıkaracaktır. Çünkü bu komut en fazla 88 karakter uzunluğunda bilgi okuyabilmektedir. Örneğin arka arkaya gelen 88 byte arasında yukarıda bahsedilen üç byte'dan biri yoksa bilgisayar hata verecektir. Buna bir çözüm, buffer'ları byte byte okumaktır. Bu da GET # ile olur. Ancak bu komut da, eğer bir byte'ın değeri sıfır ise sorun çıkarır. Bu nedenle aşağıdaki gibi bir düzeltme gereklidir:

100 GET
”
THEN A$ —- CHR$(0)

Artık tek tek direkt blok komutlarını görebiliriz...

BLOCK-READ (B-R)

Bu komut (Blok Okuma) ile daha önceden ayarladığımız buffer'ın içine disketteki bir blokun okunmasını sağlarız. Komut 15 numaralı hatta ve komut kanalından gönderilmelidir. Ancak B-R komutu okunan blokun ilk byte'ını okumaz. Bu nedenle blokun tamamını okuyan U1 komutu kullanılır. Komutun formatı şu şekildedir: “U1 kanal araç track sector”

Kanal numarası, buffer'ı isterken kullandığımız ikincil adrestir. Araç için 0 yazmamız gerekiyor. Eğer 1541 tek değil de çift sürücülü bir alet olsaydı, buraya hangi sürücüyü kullanmak istediğimizi yazacaktık. Track ve Sector numaralarını da zaten biliyorsunuz. Ancak bu sayıların hepsini onluk sistemde yazmak gerekiyor. DISKMON'daki gibi onaltılık sistem kullanmak hataya yol açacaktır. Şimdi aşağıdaki örnek programa bir göz atın:

10 OPEN 1,8,15
20 OPEN 3,8,2,
1,“U1 2018 0”
40 GET *3,A$,B$
50 PRINT ASC(A$),ASC(B$)
60 CLOSE 3
70 CLOSE 1

Sonuç olarak 18 ve 1 sayılarını göreceksiniz. Şimdi neler olduğunu açıklayalım. Önce 15 numaralı komut kanalını açıyoruz. Sonra da 2 numaralı kanaldan bir buffer istiyoruz. Buffer geldikten sonra da, 18 0 numaralı Track'ı (yani directory zincirinin ilk halkasını) buffer'a okutuyoruz. Arkasından, buffer'ın ilk iki byte'ını A$ ve B$ içine okuyoruz. Aslında bu iki byte üzerinde daha önce gördüğümüz sıfır byte'ını düzeltecek kontrolü yapmamız gerekirdi. Ancak sonucu önceden bildiğimiz için buna gerek görmedik. Son satırda da gelen byte'ları sayıya çevirip ekrana yazıyoruz. Directory'de 18/00'dan sonra gelen blok 18/1 olduğu için yukarıdaki sonucu elde ediyoruz. Sonunda da kanalları kapatıyoruz.

Yukarıdaki programın 40-50 satırlarını silip aşağıdaki satırları yazın:

40 FOR I- 70 256
45 GETİt3,A$
50 PRINT A$;
55 .

Şimdi de, 18/0'daki tüm byte'ları karakter şeklinde göreceksiniz. An-

BLOCK-WRITE

(Blok Yaz) bilgileri değiştirip yazmamızı sağlar. Önemli ve aynı zamanda tehlikeli olabilecek bir komuttur bu.

cak bu karakterlerin bu kısmı Commodore 64 için kontrol karakteri yerine geçtiğinden ekranda komik şeyler olabilir. Gene de arada bazı anlaşılır karakter dizileri olduğunu göreceksiniz. Örneğin disketin adı ve ID'si gibi. Aşağıdaki değişikliği yaparsanız, karakter yerine byte değerlerini görürsünüz:

50 PRINT ASC(A$ 4 CHR$(0));

Doğrudan ASC(A$) yazmadığımızı ve böylece kendimizi A$'in boş olması durumunda ASC fonksiyonunun yaratacağı hatadan korumuş olduğumuzu görüyorsunuz. Eğer okuduğumuz blokun tamamını karakter veya sayı olarak listelemekten başka bir şey yapamıyor olsaydık, bu komut pek bir işe yaramazdı. Öyleyse, bir başka komutu görelim...

BUFFER-POINTER (B-P) Bu komut (depo göstergeci) ile, buffer'a okuduğumuz bloktaki byte'ları herhangi birinden itibaren okumaya başlamamız sağlanıyor. Örneğin, geçmiş bölümleri hatırlarsanız, disketin adı 18/0'da 144. byte'dan itibaren 16 bir alan kaplıyordu. Önce B-P komutunun genel formatını görelim, sonra da disketin adını, 18/0'daki diğer byte'ları okuma gereği olmadan nasıl izole edebileceğimize bakalım:

kanal pozisyon

10 OPEN 1,8,15
20 OPEN
30 PRİNT #1,“Ul 20 18 0”
35 PRİNT#1,“B-P 2 144”
40 FOR TO 16
45 GET
46 IF A$- CHR$(160) THEN 60
50 PRINI A$;
55 NEXT I
60 CLOSE 3
70 CLOSE |

Görüldüğü gibi, önce 18/0'ı okuduk ve ikinci kanalın buffer'ının göstergecini 144. byte'ın üzerine getirdik. Sonra da, disketin adını ya 16 karakter oluncaya ya da SHIFT-SPACE'in karakter kodu olan 160'a rastlayıncaya kadar okuduk. B-P ile göstergeci ileri geri oynatmakta hiçbir mahsur yok. 144'e getirip disketin adını okuduktan sonra 0'a getirip bir sonraki Track numarasını öğrenebiliriz. Yani, buffer'ın içeriğini baştan aşağı seri yöntemle inceleme zorunluluğumuz yok.

BLOCK-WRITE (B-W)

Bu komut (Blok Yaz) ise, buffer'daki bilgileri değiştirip disketin üzerine yazmamızı sağlıyor. Önemli, ama kullanımı tehlikeli olabilecek bir komut. Eğer disketin üzerinde yanlış bir yere yanlış bir byte yazarsanız, programlarınızı ve hatta disketinizin tümündeki bilgileri kullanamaz hale gelebilirsiniz. Bizden söylemesi... B-W komutu da B-R gibi buffer'ın ilk byte'ında hata yaratmakta. Bu nedenle onun yerine U2 kullanılır. Formatına gelince:

“U2 kanal araç track

Dilerseniz bunun örneğini disketin adını değiştirerek görelim:

10 OPEN 1,8,15
20 ÖPEN 3,8,2,* *
30 PRİINT41,“Ul 20 18 0”
35 2 144”
36 A$— “DENEME”
40 IF LEN(A$) <16
THEN A$- A$ 4* CHR$(160):
55
GOTO 40
50 PRINT
55 1,“U2 2 0 18 0”
60 CLOSE 3
65 PRINT
70 CLOSE İ

Bildiğimiz yöntemlerle 18/0'ı buffer'a okuyup 144. byte'ına geliyoruz. A$'in içinde duran yeni disket adını 160 byte'ı ile 16 karaktere tamamlıyoruz. Daha sonra da 50. satırda buffer'a geri yazıyoruz. Satırın sonundaki noktalı virgüle dikkat! Eğer o olmazsa, ismi oluşturan 16 karakterin arkasına bir de 13 ($0D, RETURN karakterinin kodu) byte'ı eklenir, ki bunu pek de istediğimiz söylenemez. 55 numaralı satırda ise, gerçek yazma işlemini yapıyoruz ve buffer'daki yeni bilgiyi olduğu gibi 18/0'a geri yazıyoruz. Disketi initialize ederek, 1541'in disketin yeni adının farkına varmasını da sağladıktan sonra işimizi bitiriyoruz. Directory'i yükleyerek kontrol edin isterseniz...

BLOCK-ALLOCATE (B-A)

Eğer geçmiş iki bölümümüzü izlemişseniz, bu komutun ne işe yaradığını hemen anlamışsınızdır. Disketin saklı duran blok haritasında belli bir bloku dolu göstermek istersek bu komutu kullanmalıyız. Diskete bir program SAVE ettiğinizde, programın kapladığı bloklar otomatik olarak 1541 tarafından BAM'da dolu olarak işaretlenir. Daha sonra diskete yazılacak bir dosya, bu bloklara dokunmaz. Ancak biz normal yolların dışında diskette bir bloğa bir şey yazmışsak, bu bloğu korumamız gereklidir ve bu otomatik olarak yapılmaz. İşte burada imdadımıza B-A yetişir. Formatını bir görelim:

“B-A araç track sector”

Eğer dolu olarak işaretlemek istediğimiz blok daha önceden böyle işaretlenmişse, 65,NO BLOCK,TR,SE mesajı hata kanalında belirir. Burada, TR ve SE ile 1541 bize hâlâ boş duran bir sonraki en yakın blokun adresini vermektedir. Eğer diskette boş görünen bir blok yoksa, bir başka deyişle BAM'da bütün bloklar dolu olarak işaretlenmişse, TR ve SE sıfır olarak geri dönecektir.

Peki, dolu olarak işaretlemek istediğimiz blok aslında disketin üzerinde yoksa ne olacak? Örneğin 10. 82. Sector'ünün diskette olmadığını biliyoruz. Bu durumda da 66,ILLEGAL TRACK OR SECTOR,10,82 mesajını alırız.

Bu gördüklerimizi küçük bir örnekte uygulayalım:

100 OPEN 1,8,15
110 INPUT “TR,SE”;T;S
120 PRINT #1,“B-A 0”;T;S
130 INPUT #1,A,B$,TR,SE
140 IF A—0 THEN 190
150 IF A<>65 THEN
PRINT A,B$,TR,SE:
GOTO 210
160 IF TR-0 THEN
PRINT “BOŞ BLOK
GOTO 210
170 IF TR- 18 THEN
TR - 18:SE-0
180 T-TR:S—-SE:GOTO 120
190 PRİNT T;S; “DOLDU!”
200 #1,“1”
210 CLOSE 1

Neler yaptık?.. Önce komut kanalı açılıyor. Görüldüğü gibi bir blok okumayacağımız için buffer'a ihtiyacımız yok. 110'da dolu gösterilecek Track ve Sector kullanıcıdan alınıyor.

Şu ana kadar

anlatılan komutlar

pratik, herkesin

kullanabileceği

komutlardı. Şimdi sıra geldi profesyonel olanlara.

Sonra da komut kanalından 1541'e B-A komutu gönderiliyor. 120. satıra dikkat! Track ve Sector numarasını değişken olarak da yazabiliyoruz!.. 130'da da hata mesajını okuyoruz. Eğer hata yoksa, 190'a gidip hangi blok için işaretleme yapıldığını gösteriyoruz. Ancak hata mesajı varsa ve bu 65 numaralı mesaj değilse, 150. satırda mesajı yazıp çıkıyoruz. Eğer 65 numaralı mesaj gelmişse, ama TR numarası 0 ise boş blok kalmamış demektir ve 160. satırda program biter. 170'e geldiğimizde, hata mesajının bir sonraki blok olarak directory zincirinden bir blok seçmesi olasılığına karşı önlem alıyoruz. 180'de de, tüm işlemi bir de yeni blok için deniyoruz. Sonuç olarak, ya kullanıcının verdiği ya da ona en yakın blok (eğer hâlâ boş blok varsa) dolu olarak işaretleniyor ve kullanıcı olup bitenden haberdar ediliyor. Peki, bu dolu olarak işaretlediğimiz, ama aslında bir dosyanın parçası olmayan bloklar ne zamana kadar böyle korunabilirler? Bir sonraki VALIDATE komutuna kadar! Çünkü bu komut, bir dosyaya ait olmayan her bloku boş olarak işaretlemektedir. Dolayısıyla, birbirinden kopuk bloklar kullandığınız disketlerinizi OPEN 1,8,15,“V”:CLOSE 1 ile validate etmemeniz tavsiye olunur...

BLOCK-FREE (B-F)

Bu komut, B-A'nın tam tersi. Daha önce dolu olarak işaretlenmiş (ya sizin tarafınızdan, ya da otomatik olarak) bir bloku tekrar boş göstermeye yarar. Formatı da hemen hemen aynı:

“B-F araç track

Örnek mi istersiniz?..

10 OPEN 1,8,15
20 PRINT #1,“B-F 0 10 10”
30 PRİNT #1,“1”
40 CLOSE |

10/10 numaralı bloku boş gibi gösterdik. Eğer blok daha önce de boşsa, bu bir hata mesajına yolaçmayacaktır. Ama 10/80'i boşaltmaya çalışsaydık. 66 numaralı mesaj gelirdi. Eğer bu komutu kullanarak, bir dosyayı oluşturan bloklardan birini boş göstermişseniz, daha sonra bu diskete bir başka dosya SA VE ettiğinizde, bu blok yeni dosya için kullanılabilir. Bu durumda, eski dosyayı oluşturan blok zinciri kopacaktır ve o dosyanın geri kalan bloklarını hiç geri gelmemek üzere kaybetmiş sayılırsınız. Eğer yeni dosyayı göndermeden validate yaparsanız, eski dosyaya ait bloklar tekrar dolu olarak işaretlenecektir.

BLOCK-EXECUTE (B-E)

Şu ana kadar kullandığımız komutlar her eve lazım, pratik, herkesin kullanabileceği komutlardı. Bundan sonra gelenler ise, profesyonel kullanımlar için. Makina dilini ve en önemlisi 1541'in işletim sistemini, örneğin DOS dökümünü iyi bilmeyi gerektiriyor. Biz burada sadece komutları kısaca açıklayacağız. Böylece ne tür komutlar olduğunu görebilirsiniz. Eğer daha derine inmek ve 1541'e açık kalp ameliyatı yapmak isterseniz, TELETEKNİK'ten bulabileceğiniz “Insight the 1541” kitabına ve özellikle bu kitaptaki DOS dökümüne başvurmanız gerekiyor. Tabii İngilizce biliyorsanız... B-E ile disketteki bir bloktan bir makine dili programı 1541'in buffer'- ına yüklemek ve orada çalıştırmak mümkün. Formatı:

“B-E kanal araç track

Makina dili programlar belli adreslerde çalıştığı için, programın hangi buffer'a doldurulacağı da önemli. 0-3 arası buffer'lar 1541'in içinde $300- $7FF (768-2047) adresleri arasını kaplarlar ve 256'şar byte uzunluktadırlar. Örneğin 2 numaralı olan $500- $5FF arasını kaplar. Eğer disketinizde 19/02 blokunda bu adres aralığında çalışacak bir makina dili program varsa, aşağıdaki program onu yükleyip çalıştıracaktır (isterseniz gerçekten denemeyin...):

10 OPEN 1,8,15
20 OPEN 3,8,2,* 42”
30 INPUT #1,A
40 IF THEN
PRINT “BUFFER DOLU!”':
GOTO 60
50 PRİNT # 1,“B-E 2 0 19 02”
60 CLOSE 3
70 CLOSE |

MEMORY-READ (M-R) Bu bellek okuma komutu ile, 1541? in ROM ve RAM'indeki bilgileri okuyabilirsiniz. Formatı:

“M-R CHRS(LO) CHRS$(HI)”

Örneğin 1541'in RAM'inin 762 ve 764 numaralı adreslerinde o an içeride bulunan disketin kaç boş blokunun olduğu yeralır. İsterseniz onu okuyalım:

10 OPEN 1,8,15,*1”
20 A— 762
30 HI—INT(A/256)
40 LO— A-256*HI
50 PRİNT.#1,“M-R”;
CHRS(LO);CHRS$(HI)
60 1,A$
70 Al - ASC(A$ 4 CHR$(0))
80 A—764
90 HI—-INT(A/256)
100 LO — A-256*HI
110'PRİNT #1,“M-R”;
120 GET # 1,B$
130 A2 — ASC(B$ 4 CHR$(0))
140 PRİNT Al -256*A2
150 CLOSE 1

Artık programın incelenmesini size bırakıyorum. Bu komuta bir parametre daha ekleyerek kaç byte okumak istediğinizi de belirtebilirsiniz. Onu da aşağıdaki örnek ile görelim. Bir disket initialize edilince, disketin adı $780'den itibaren 1541'in belleğine yazılır. $790'ü LO/HI olarak ayırırsak 144/7 elde ederiz.

10 OPEN
20 PRİNT
CHRS$(7);CHRS(16)
30 INPUT #1,A$
40 CLOSE |
50 PRINT A$

Görüldüğü gibi, okunacak byte miktarı gönderilince, GET ## yerine INPUT & kullanabiliyoruz.

MEMORY-WRITE (M-W)

Bu komutla da, 1541'in RAM'indeki bazı bilgileri değiştirme imkânı vardır. Genel formatı:

“M-W CHRS$(HI) CHRS(datal) CHRS(data2)....”

LO ve HI ile M-R'de olduğu gibi RAM'daki adresi belirtiyoruz. Adet parametresi, arkadan kaç byte yazılacağını belirliyor. En fazla 34 olabiomut kanalı en fazla 40 arakter kabul eder. Bunun ilk altısı komutumuzun altı karakteri tarafından kullanılır.

lir. Bunun nedeni komut kanalının en fazla 40 karakter kabul etmesi ve bunun ilk altısının komutumuzun ilk altı karakteri tarafından kaplanması. Bir örnek görelim. Disketin araç numarası (yani 8) 119/120 adreslerinde saklanmaktadır. 119'da 120'de de 84 64 — 72 vardır. Bunu değiştirerek, 1541'e başka bir araç numarası ile hitap edebiliriz. Örneğin bunu 8 yapalim:

10 OPEN 1,8,15
20 PRİNT #1,“M-W”;
19);CHR$(0);
CHRS(2);CHR$( 32);
CHR$(9 4 64)
30 CLOSE |
40 OPEN 1,9,15
50 PRİNT # 1,“1”
60 CLOSE 1

Artık her türlü işlemde 8 yerine 9 kullanmanız gerekecek. Tabii, 1541'i kapatıp açarsanız tekrar eski haline döner.

MEMORY-EXECUTE (M-E)

Bu komutla da, 1541'in RAM'inde veya ROM'unda olan bir programı çalıştırabilirsiniz. Formatı:

“M-E CHRS$(LO) CHRS(HI)”

Örneğin, 1541'in işletim sisteminde $EFC9 adresinde 72 numaralı DISK FULL mesajını gönderen rutin vardır. Bunu çalıştıralım:

10 OPEN 1,8,15
20 PRİNT
CHR$(201)CHRS(239)
30 INPUT #1,A,A$,B,C
40 PRINT A,A$,B,C
50 CLOSE |

İstediğimiz mesajın oluştuğunu göreceksiniz.

USER (U)

Bu komut, kullanıcının belli adreslere yerleştirdiği bir programı otomatik olarak başlatmasını sağlar. Formatı:

Buradaki X yerine A-J arası bir harf veya 1-9 arası bir rakam veya “U” gelebilir. Her defasında da başlatılacak programın başlangıç adresi aşağıdaki tablodaki gibi olur:

A VEYA U1 - $CD5F B VEYA U2 - $DC97 C VEYA U3 - $0500 D VEYA U4 - $0503 E VEYA U5 - $0506 F VEYA U6 - $0509 G VEYA U7 - $050C H VEYA U8 - $050F I VEYA U9 - $FF01 J VEYA U: - $EAA0

U1/U2 (veya UA/UB) komutlarını biliyoruz. Diğerlerinden bizim için ilginç olan UJ. Çünkü bu, 1541'i açılış durumuna getirecek RESET'i yapıyor.

10 OPEN 1,8,15
20 PRİNT #& i,“UJ”
30 FOR Il TO 1000
40 NEXT |
50 INPUT #$ 1,A,A$,B,C
60 PRINT A,A$,B,C
70 CLOSE |

30-40 arasında reset işleminin bitmesini bekliyoruz. Sonra da hata kanalını okuyoruz. Gelen mesajın 73, CBM DOS V2.6 1541,00,00 olması gerekiyor. Hoşçakalın...