Atölye

Vedat Hallaç rabilirsiniz. Ya da komutların yorumlandığı rutinin öncesine kısa bir casus rutin koyup, sizin komutunuz geldiği zaman kontrolü bilgisayardan alabilirsiniz. $0073'ü bile değiştirmeniz mümkün. Tabii ki bu hiç de iyi bir fikir sayılmaz. Kontrol ettiğiniz komutun (mesela (9XS) bir PRINT'in parametresi olup olmadığını, bir değişkene verilen değer olup olmadığını ya da benzeri binlerce şeyi kontrol etmeniz gerekeceğinden, sağ kulağınızı sol ayağınızla göstermek olur bu. Benim size önereceğim, komut eklemenin en basite indirgenmiş şekli: $0308-$0309'da size RETURN'e basar basmaz girilen satırı yorumlayan (ya da duruma göre BASIC satırını alıp onu yorumlayan) ROM rutininin adresi bulunur. Eğer bu adresi bir yere not eder, daha sonra $0308-$0309'u bizim rutinimizi gösterecek şekilde değiştirirsek, bilgisayara girilen satır hakkında fikrini belirtmeye çalışmadan önce bizim rutinimiz ön kontrol yapma hakkına sahip olur. Eğer bizim rutinimizden çıkarken her şeyi bir sonraki komutu gösterecek şekilde ayarlarsak ve kontrolü ROM rutinine bırakırsak tüm komutlar olduğu gibi işleyecek, sadece gerekli durumda fazladan bazı komutlar işleme sokulacaktır. İsterseniz yaptığınız işi basit bir örnekle pekiştirelim: Biliyorsunuz bankamatikler kartı alır almaz şifreyi girmenizi beklerler. siz şifreyi girdikten sonra (yani “giriş” tuşuna bastıktan sonra) kart üzerinde ya da merkezde yazılı olan şifreyle sizin girdiğiniz şifreyi karşılaştırırlar. Eğer şifre doğru dedi olayı biraz çarpıtalım: Diyelim ki siz bu niz, ya da programa dışarıdan müdahale etmek yetkiniz var. Tekrar farzedelim ki, şifrenin doğru olup olmadığını kontrol eden runıyor (yeterince komik oldu mu, devam edeyim mi?). Bu adresi bir yere not edip, kendi program adresinizi buraya girerseniz, şifreler kontrol edilmeden önce çalışacak bir programınız olur. Bu programda, girilen şifrenin “1234” olup olmadığını kolaylıkla kontrol edebilirsiniz. Eğer girilen şifre bundan farklıysa demin bir kağıda not ettiğiniz adrese sıçrarsınız ve bütün işlemler normal olarak yerine getirilir. Ama girilen şifre “1234” se şifre kontrol rutinine hiç sıçramadan ana programa sıçrarsınız. Böylece bankamatiğe bir “komut” eklemiş olursunuz. Bu eklenen komut, “şifre olarak 1234 girildiyse, doğru olup olmadığına bakma” diye bir işlem yapmaktadır. Bu sayede gidip istediğiniz kartı alıp, bankamatiğe “1234” şifresini girerek şifre korumasını atlayabilirsiniz. Başka şifre girenler ise böyle bir hilenin mümkün olduğunu bile bilmeden işlemlerini normal olarak sürdürecektir. Bizim Commodore BASIC'e yaptıracağımız işlem de tam anlamıyla budur. Bir komut girilir girilmez bilgisayara “Dur bir dakika!” diyerek araya girecek, gelen komutun bizimki olup olmadığına bakacak, bizimki gelmediyse kontrolü bilgisayara devredeceğiz. Komut bize aitse bilgisayara “Bu iş seni ilgilendirmiyor. Sen gidebilirsin” dedikten sonra istediğimiz işlemi yapacağız. Gelen komutla ilgili tüm kanıtları yok ettikten sonra da her şeyden habersiz olan bilgisayara hiç bir şey olmamış gibi yoluna devam etmesini söyleyeceğiz. Bu şekilde söyleyince kolay olacakmış gibi görünüyor, ama aslında hiç de kolay değil. Bütün bu işleri yapabilmek için bilgisayarın komutları ne şekilde işlediğini öğrenmeliyiz. $0308-$0309 adreslerini incelediğimizde burada $ATE4 değerini buluruz. $A7E4'ün en başında ise

JSR $0073

komutu yer almaktadır. $0073'te yer alan rutin, bilgisayarınızda yer alan tek RAM rutinidir. Bu rutinin RAM'de yer almasının sebebi de kendini değiştiren bir rutin olmasıdır. $0073'e her sıçradığınızda ilk olarak $007A-$007B birleşik adresinde yer alan değer bir artırılır, sonra da bu iki adresin gösterdiği bellek alanında yer alan karakter alınır. Bu alınan bayt (ya da karakter) $20 değilse, baytın sayı ya da karakter olmasına göre bazı flag'lerin durumları ayarlanır. rutinden dönüldüğü anda A registerinde (Akümülatörde) alınan bayt bulunur. Bu rutinden dönüşte A'da hiçbir zaman $20 bulunmaz. Eğer bu rutin ROM'da yer alsaydı, kendi kendini değiştiremeyecek, dolayısıyla çalışmayacaktı. Madem ROM rutini bu komutla başlıyor, biz de programımızı bu komutla başlatalım. Daha sonra A'da istediğimiz karakterin olup olmadığını kontrol edelim. Tabii ki önce ekleyeceğimiz komutun ne olacağına karar vermeliyiz. Bildiğiniz gibi Commodore'a eklenen komutların sayısı iki-üç gibiyse genelde yana ok tuşu arkasına konan bir harf şeklinde komutlarımız olur (“e-A” gibi). Belki de ilk teyp turbolarından olan pinky turbo'- nun LOAD, SAVE ve VERİFY yerine * ve “ kullanması yana ok standardını başlatmıştır. Sebebi ne olursa olsun, çoğu kullanıcı gi-

LDA
STA
LDA
STA
RTS
LDA
STA
#S16
S0308
#SCO
#SE4
#SAT
JSR 80073
$COSO
$CO53
$CO56
$CO59
$Co5C
JSR $0073
$CIE4 JSR

Tablo-1: Grafik işlemlerini komut haline getirmek için eklenmesi gereken komutların hepsi.

$C100
$C12D
$C146
$C19B
$CIE4

bi ben de yana ok tuşunun büyüsüne kapılanlardanım ve komutların “ “ B”, RI,R2,R3” ve X,Y,RENK” olmasına karar verdim. İtirazı olan varsa beri gelsin. Komutların beşi de yana ok ( klavyenin sol üst köşesinde yer alan tuş) ile başladığından, programımız JSR $0073'den hemen sonra bu karakterin olup olmadığına bakmalı. Bu karakterin kodu $5F olduğuna göre CMP 5F gibi basit bir komutla BASIC eklemesinin ilk adımı atılmış oldu. Bu satırdan sonra gelen BEO Komut-Olabilir yardımıyla, eğer yana ok karakteri varsa A, B, C, D ve E harflerinin kontrol edileceği yere sıçrıyoruz. Tabii ki karakter beklediğimiz yana ok değilse, komutun BASIC'e ait olduğuna karar vererek kontrolü BA-SIC'e bırakıyoruz. Tabi ki not aldığımız $ATE4 adresine sıçrayarak değil. Gizli bir iş yaparken arkanızda iz bırakmamayı öğrenmelisiniz. Casus rutinimiz en başta yer alan JSR $0073'ü gerçekleştirdiği için (ve A'da yer alan baytı hâlâ kaybetmediğimiz için) $A7ET'ye sıçramalıyız. Bu işlemi yaptığımızda, eğer komut bize ait değilse BASIC için hiçbir şey farketmeyecektir. SA7E7T'de yer alan rutin (bütün aptallığıyla) $0073'e sıçradığını ve A'da yer alan baytın buradan geldiğini sanacaktır (“Bak, kuş!” numarasının bundan daha etkili olduğu bir alan daha yoktur sanırım). Bundan sonra olacaklar bizim rutinimizi kesinlikle ilgilendirmez. Eğer normal bir kömut verildiyse bu komut işletilecek, hatalı bir şeyler girildiyse de ?SYNTAX ERROR'la karşılaşılacaktır (Girilen “hatalı bizim komutumuz olmadığı “zamanlar). Bizim komutumuz girilmediği zaman işlerin yolunda gitmesini kolayca sağladık. Peki girilenler bizim komutlarımızsa ne yapacağız? Eğer sıfırdan rutinler yazıyor olsaydık işimiz kolaydı: Komutla ilgili tüm işlemi bitirin, $007A-$007B'yi komutumuzun sonrasında bırakıp SA7E4'e sıçrardık, olurdu. Oysa şu anda hazır bir rutin var (beş ko-

"mutluk grafik paketi) ve bu rutinde gerekli komutun işlemini yaptıktan sonra ROM'a geri dönmeliyiz. Bunu nasıl yapabiliriz? Bu işi yapmanın en kolay yolu, ilgili rutini JSR ile çağırdıktan sonra ROM'a JMP ile sıçramaktır. Bunu yapmak yeni yeni teorik bilgi yüklenmekten kolay olabilir. Ama ben birbirinin aynı beş ayrı komutu ard arda vermenizi engellemek için (ve kafanızı biraz meşgul etmek için) yeni bir komut anlatmak istiyorum. JSR Komutu ve Yığıt (Stack)

Bilgisayarınızın alt programlardan geri dönerken nasıl olup da yerini unutmadığını hiç düşündünüz mü? Ya da bir interrupt oluştuğunda kısa interrupt servis rutinini çalıştırıp sonra hiçbir şey olmamış gibi aynı yere dönebildiğini? Bir yerlerde sizin hafızanıza karışmadan bekleyen ve bu işleri düzenleyen bir hafızaya ihtiyaç vardır Commodore'unuzun. Bu ek hafızaya STACK adı verilir. Sadece C-64'ün değil, tüm bilgisayarların temelde aynı mantığı kullanan yığıtları bulunur. Kimi bilgisayarın tüm RAM'i yığıt olarak kullanabilirken, kiminin onlarca ayrı yığıtı bulunabilir. Fakat bunlar içinde anlaşılması en basit olanı ve en sabit olanı C-64'ün yığıtıdır sanırım. $0100-$01FF arasında yer

19 alan yığıt, $O1FF'den aşağı doğru genişler. — ye çalışırken de yığıtta yer alan değerlerden — larımızdan üçü hatasız bir şekilde çalışabi- Yani yığıta bir değer atmaya kalkarsanız yığıt — faydalanacak. Tabii ki bu değerler bizim yı- — liyor. Yani yapılan en ufak bir değişiklikte bir alt bayta geçer. Yığıtı bir tabak yığını ola- — ğıtta sakladığımız değerlerden başkası olma- — bu üç komut çalışma yeteneğini kaybediyor. rak düşünebilirsiniz. Her koyduğunuz tabak — yacak. Böylece bilgisayarımızı iyice dolan- — Neyse ki asıl problem çıkartan kısım virgül bir diğerinin üstüne gelir. Daha sonra buta- — dırmış olacağız. kontrüllerinin ilki. Yani bunu kaldırdığımızbak yığınından bir şeyler almaya kalktığınız- İsterseniz bu anlattıklarımı Tablo 1'deyer — da (daha doğrusu JSR $0073 ile değiştirdida, sadece en üstteki tabağı olabilirsiniz. Yani ard arda üç değeri yığıta attığınızda, aldığınız ilk değer üçüncüsü olur. Yığıt konusunu detaylı olarak makine dili kursunda ele alacağım, bu yüzden şimdilik bu kadarı yeterli olacaktır. Şimdi de bilgisayarınızın kaldığı yeri unutmamak için nasıl bir yöntem izlediğine göz atalım: Bildiğiniz (ya da şimdi öğreneceğiniz) gibi bilgisayarınızın PC adı verilen 16 bitlik bir registeri vardır ve o anda işletilmekte olan komuta ait bilginin bulunduğu adresi gösterir bu register. BASIC'teyken SYS 49152 verdiğinizde, PC'ye $CO0O değeri atanır sadece (aslında bu yapılan işlemden çok bir sonuçtur). Fakat, PC sadece tek bir değeri aklında tutabildiği için, alt programlara gitmeden önce, bir şekilde nereye geri dönmesi gerektiğini hatırlayabilmelidir. Bunun için demin anlattığım yığıt kullanılır. Alt rutine sıçranması gerektiğini gösteren JSR komutu görüldüğünde bunu takip eden iki bayt alınır ve ikinci bayt gösterilirken PC'nin sırasıyla yüksek ve düşük değerlikli baytları yığıta atıhır. Bu baytlar yığıtta yukarıdan aşağı doğ- Tu yer alacağından, 6508 için standart olan düşük-yüksek değerlikli bayt sistemi konmuş olur. Tabii ki yığıta atıldığı anda JSR'yi takip eden ikinci baytı gösteren PC, bir sonraki komuttan bir bayt geridedir. Yani yığıtta yer alan değer bir artırıldığında alt programdan geri dönüldüğünde işletilecek komutun adresi elde edilir. Alt program, işini bitirdiği zaman bir RTS komutuyla bunu belli eder. RTS komutu hemen yığıtta yer alan iki baytı alır, bunları doğru sırada PC'ye yerleştirir, PC'yi bir artırır ve programın çalışmasına devam eder. Nereden mi? Tabii ki JSR komutunu takip eden komuttan. Bu yüzden alt programlara girerken kaç tane değeri yığıta attıysanız bu kadar değeri yığıttan çekmelisiniz. Yoksa, bilgisayarınız sizin yığıtta sakladığınız verileri alıp, bu verilerin adresine sıçramaya çalışır RTS'yi görünce. Bizim komut ekleyicide yapmayı düşündüğümüz işlem de tam anlamıyla bu, RTS ile BASIC'e döneceğini sanan grafik rutinlerine sıçramadan önce yığıta ROM'da dönülmesi gereken yerin adresini atacağız. Grafik komutlarını da JSR ile değil, JMP ile çağıracağız. Böylece bilgisayar bu rutinlerin nereden çağrıldığını hatırlayacak. Geri dönmealan programda da takip etmeye çalışın. Eğer takip edemezseniz, beni izlemeye devam edin. İlk olarak SA7 ve $E3 değerlerini yığıta atıyoruz (PHA komutu A'yı yığıtın en son değeri olarak tanımlar ve yığıtı bir aşağı indirir). Böylece RTS görüldüğü anda SATE3 4 1-$ATE4 adresine sıçranacağını garanti ediyoruz. Demek ki grafik bittiğinde, $7A-$7B'yi gerektiği şekilde bırakırsak (ki bırakmayacağız) RTS görüldüğünde komutumuz hiç işlenmemiş gibi yoluna devam edecek ROM. Buraya kadar da her şey kontrol altında.

Şimdi A, B, vb. kontrolünü yapalım. Demin JSR $0073 ile yana ok karakterini bulduğumuza göre bu harfle olan işimizi bitirdik. Şimdi sıradaki harfi alalım:

JSRS$0073
ve “A” olup olmadığını görelim:
CMP #41
BEO$COS0

A değilse:

CMP # 42
BEO$COS3

Eğer A, B, C, D ya da E değilse: RTS

Yani ROM'a: “Komut bize ait değil, yana okunuzu ve bir sonraki harfi yedim. Kalanıyla ne yaparsanız yapın” diyerek kaçıyoruz. Neyse ki ROM'da yana ok'la başlayan bir “komut yok. Sonuç zaten bir ERROR olacaktı. İki karakter eksik ya da fazla olmuş, bir hata için farketmez. Tablo 1'de de rahatlıkla görebileceğiniz gibi $C0S50'den itibaren grafik işlemlerine JMP'ler yapılıyor. Bu rutinlerden ilk üçü, yani kullanıcıdan bir parametre istemeyenler oldukları gibi çalışabiliyor. Ama kullanıcının bazı şeyleri girmesini bekleyen son ikisi SYNTAX ERROR veriyor. Bunun sebebi, BASIC'in bir komutla işi bittiğinde $7A ve $7B'yi yeni komutun ilk karakterinde bırakması, oysa bizim rutinin eski komutun son karakterinde bırakması, Bu işi kolayca halledebileceğini sanan arkadaşlarınız yanılıyor, çünkü komutğimizde) problemi halledebiliriz. Hem hoş bir yan etkisi de oluyor. Komutumuz: değil, «—D 1,2,3 olarak çalışır. Yani tam bir komut gibi... Ama nedense bu kadarla kalmıyor problemler. komut işini bitirdikten sonra (gene bu son iki komutun marifeti bu) $7A-$7B'yi gerekenden bir ileride bırakıyor. Bu yüzden de komuttan sonra gelen iki nokta üstüste (:) farkedilmiyor ve alıyorsunuz SYNTAX ERROR'u. Grafik rutinleri üzerinde oynamadan bu hatayı düzeltemeyeceğimi farkedince, bir hile buldum. Her «-D ve &«E komutundan sonra iki kere iki nokta üstüste koyarsanız ve sonraki komutu öyle girerseniz, ya da sonraki komut diye bir şey yoksa bir tane iki nokta üstüste kullanırsanız bu SYNTAX ERROR'dan kurtulabilirsiniz. Her ne kadar can sıkıcı bir kullanım tarzıysa da en kolay bu şekilde hatadan kurtulabiliyoruz. Tabii ki hazır yazılmış bir programı komut haline çevirmiyorsanız, bu tür hatalardan kurtulmanız çok kolay. Hatayı farkeder farketmez başını ezebilirsiniz, ya da komutların $7A'yı bıraktığı noktayı aynı tutabilirsiniz. Ama bir programı fazla değiştirmek istemediğinizde bu tür hatalarla karşılaşmanız çok normaldir (özellikle de parametreleri okuyanlarda): Bu eklemeleri de yapınca grafik komutlarınız tam olarak komut halini almış oldular: Grafik ekranı açma. «-B: Grafik ekranını kapama. Grafik ekranını temizleme. «-D,RI,R2,R3: Çok renk modunun renklerini belirleme. #-E,X,Y,R: X,Y koordinatına R renkli nokta koyma (R - 0 ise silme). Son bir şey daha var: RUN/STOP-RESTORE kombinasyonu $0308-$0309 adres çiftinin değerini düzeltmez. Yani bilgisayarınızı RESET'leyene kadar, ya da doğru değeri bu adreslere girene kadar eklediğiniz komutlardan kurtulamazsınız. Bu yüzden $C0OOB adresinde bu adreslerin değerini düzelten rutini de ekledim. Bu aylık yazımız da bu kadar. Gelecek ay hepinizle görüşmek üzere hoşçakalın.

erkese merhaba. Hatırlayacağınız gibi geçen sayıda polinomların yardımıyla bazı yılarının nasıl hesaplanacağı konusuna ise yazımda değinmeyeceğim, çünkü türev almayı çok iyi bilmeden bu polinomların katsayılarını hesaplayamazsınız. Eğer bu konuyla ilgileniyorsanız Ve fonksiyonların türevlerini rahatça alabiliyorsunuz ya Taylor ve McLaurin serileri konusunda ufak bir araştırma yapın, ya da bana yazarak basit bir şekilde katsayıların nasıl hesaplanacağını öğrenin. Ama bilgisayarınıza yeni fonksiyonlar eklemek gibi bir niyetiniz yoksa (ARC-COS gibi) bu fazladan bilgiye ihtiyacınız olmayacaktır. Eğer bir fonksiyon eklemeyi kafanıza koyduysanız, fakat matematik kısmından sıkılıyorsanız, ekleyeceğiniz fonksiyonun katsayılarını tanıdığınız bir matemasiniz. Bana bu konuda da yazabilirsiniz, fakat size vereceğim cevap bir matematik öğretmenininki kadar garantili olmayacaktır. Zaten büyük bir çoğunluğunuz bu konuda Geçen sayıda sizlere sorduğum faktöriyel hesaplama rutini konusunda hiç mektup ulaşmadı elime. Ama gene de size söz verdiğim gibi gelecek sayıya kadar bekledikten sonra doğru (en doğrusu olmasa da) rutin ve (eğer yollarsanız) sizin çözümlerinizi yayınlayacağım. Kısacası beklemedeyim. Eğer belli bir yerinde takıldıysanız, takıldığınız yer konusunda da bana danışın. Bu kadar çok konuda “bana yazın', *bana sorun' gibi lafları söylememin sebebi, sizlerden gelen mektupların arkasının kesilmiş olması, Sizlerden gelen bir yönlendirme olmadan konu seçiminde körlemesine gitmekten başka çarem kalmadığını uzun zamandır söylüyorum. Yaklaşık iki aydır sizlerden mektup olmadığım için bu konuların büyük bir kitleye hitap edemediğini düşünmeye baş-

om

Vedat Hallaç ladım. Bu yüzden gelecek sayıdan itibaren bu yazıyı bitirmeyi ve yeni Commodore'cular için bir makine dili kursuna başlamayı düşünüyorum. Bu kurs, makine dilinden hiç anlamayanlara göre düzenlenecek. Makine dili öğrenmek için çırpınan arkadaşlarınızı da belli bir seviyeye getirdikten sonra ROM'- un kullanımı gibi konulara geri döneceğiz. Gelecek sayıda bu konuda daha ayrıntılı bilgi bulabilirsiniz. Bu sayıda basit bir polinom hesaplatma örneğini verdikten sonra makine dilinin gerçekten de işe yarar konularda kullanılabileceğini gösteren bir program inceleyeceğiz. Son olarak da ROM'da bulunan önemli rutinlerin adreslerini ve bazı sabitlerin bulunduğu yerleri içeren bazı tablolarımız olacak. Hepimize kolay gelsin. Biliyorum, hepiniz polinom hesaplamaktan bıktınız, çünkü görünürde pek bir işinize yaramıyor. Ben de polinom hesaplamaktan bıktım, çünkü kullanıcı aşamasında gerekten de işe yaramıyor. Ama başladığımız işi tam olarak bitirmek için son bir polinom örneği daha yapmamız gerekiyor. Ayrıca, bu son örnekteki tipte bulunan polinomlar, çoğu fonksiyonun hesaplanmasında kullanılırlar. Bazı polinomlar aşağıdaki formda bulunabilir:

İ 34a2xx 174... Bu polinomu yeniden düzenlersek:

ral 2 *a3x(X12)134...)

Bunu hesaplamak için X yerine X 2koyarak polinomun değerini hesapladıktan sonra sonucu Y ile çarpmanız gerekir. Daha doğrusu ROM'da bu işi yapacak rutin bulunmasaydı yukarıda saydıklarımı yapmanız gerekecekti. Çoğu fonksiyonun polinomu bu formda olduğu için ROM'unuzda bu tip polinomların değerini hesaplayacak program hazır olarak kullanılmayı bekliyor. Bu şekilde tanımlanan bir polinomun değerini hesaplamak için geçen sefer anlattığım türde bir yapı oluşturduktan sonra (Başta polinomun derecesi, sonra da katsayılarının bulunduğu yapı. Hatırladınız mı?) $E043 adresine sıçramanız gereklidir. Bu polinomların işe yarayabilmesi için giriş değerinin belli sınırlar içine getirilmesi gereklidir. Periyodik bir fonksiyon kullanıyorsanız bu işi yapmak siiçin problem olmayacaktır. Mesela SIN (3 Xpi)'yi hesaplamaya çalışmak yerine SIN (pi)'yi hesaplamak yerinde olacaktır. Tabii ki ROM'da bulunan SIN fonksiyonu bu ayarlamaları sizin için yapacaktır. İsterseniz örneği bir an önce vereyim de bu sıkıcı konudan kurtulalım. Polinomumuz şöyle bir şey olsun:

Y-6Xx40.5xx13-0.11xx17

Bu polinomda ilk olarak x 5'li terimin eksik olduğunu farketmenizi bekliyorum. Bu katsayı yerine sıfır koyarsak polinomumuz şu şekle girecektir:

7 bu polinomu hesaplayan rutini yazmak çocuk oyuncağı. Tablo 1'e bakın.

*-828
POLY2-$E043
LDA #<KATSAYI
LDY #>KATSAYI
JMP POLY2
*BYT 3 derecesi
*FLP -.11 ;son katsayı
*FLP O
*FLP 0.5
.FLP 6
KATSAYI
katsayı

Tablo-1: Örnek polinomun değerini hesaplattıran program.

Geçen sayıda sizin assembler'ınızın .FLP gibi bir işlemi olmayabileceğini söylemiştim. Eğer bu işlem assembler'ınızda yer almıyorsa sayıların değerini şu yöntemle bulabilirsiniz: 1. BASIC'de hiç değişken yokken “A” komutunu girerek A değişkenine ikilik gösterimini bulmak istediğiniz sayıyı yerleştirin.

2. Bir monitör programına girin. Kartuşunuzun böyle bir programı varsa onu kullanın, yoksa 1. basamağı yapmadan önce monitör programını belleğe yükleyin ve BASIC'de kalın. 3. $2D-$2E adreslerinden yararlanarak ilk değişkenin yerini öğrenin. 4. Bu değişkenin harflerinden sonra gelen (hatırlarsanız ilk iki bayt değişkenin harflerini tutuyordu) beş baytın değerini bir yere not edin. Tablo 1'de de görebileceğiniz gibi polinom derecesi olarak 7 değil de 3 kullandık. Bunun sebebi, polinomu başta gösterdiğim gibi ayırdığınızda x 7'li terimin (X 12) 1 3 olarak görünmesidir. : Birkaç değer için fonksiyonumuzu denersek şu sonuçları elde ederiz: USR(0) =0 USR(1) =6.39 USR(2) = 1.92 USR(.75) =4.69625427 Daha kullanışlı konular da var... Kayan noktalı gösterimle ilgili konumuzu kapatırken çoğu zaman karşınıza çıkan bir problemin çözümünde makine dilinin ne kadar faydalı olacağını göreceğiz: Sayılarla dolu bir diziyi sıralamak. Makine dili programımız Tablo 2'deki rutinin yaptığı işi gerçekleştirmeye çalışacak.

100 FOR I-1 TO N : FL-0
110 FOR J-N TO I STEP -1
120 IF A(J-1)>A(J) THEN H-A(J)
130 NEXT J
140 IF THEN RETURN
150 NEXT I : RETURN

göre, bu sayıyla bir karşılaştırma daha yapmak pek de akıllıca olmayacaktır. Bu yüzden iç döngünün değeri son sayıdan ilk döngünün değerine kadar değişiyor yalnızca. Bu sayede karşılaştırma sayısını azaltarak hızı artırıyoruz. Bu işlemi yapılan bir ek daha var. Her “en küçük bulma” işlemi başında bir flag'i sıfırlıyoruz. Eğer yer değiştirme olursa bu flag'in değerini 1 yapıyoruz. Eğer “en küçüğü bulma” işlemi bittiği halde bu flag sıfırsa, bu taramada hiç yer değiştirilme yapılmamış olduğunu ve dolayısıyla dizinin sıralanmış olduğunu anlıyoruz. Bu karşılaştırma, özellikle yarı sıralı dizilerde dikkate değer bir hız artışı sağlıyor. İlk taramamız N'inci elemandan 0'ıncı elemana kadar tarıyor. İkinci turda ise N.'den 1.'ye kadar taranıyor ve bu işlem bu şekilde sürüyor. İsterseniz ilk olarak bazı koşullar koyarak bu sıralama rutinini olabildiğince basitleştirelim: 1. Dizimiz, dizi listesindeki ilk eleman olmalı.

2. Dizimiz tek boyutlu olmalı. 3. Dizimiz noktalı sayılardan oluşmalı (Tam sayı veya string'ler bu kuralları ihlal eder). Eğer dizilerin bellekte nasıl saklandığını hatırlarsanız (ya da geçen sayıyı bir daha

A(I)SA(J-1) : A(J-1)-H

Tablo-2: A(N) dizisini sıraya sokacak BASIC alt programı.

Bu program A(N) dizisinde yer alan sayıları küçükten büyüğe doğru sıralayacaktır. Çalıştırmak için ise sadece GOSUB 100 demeniz gereklidir. Rutin, en basit algoritma olan kabarcık sıralama (namı diğer BUBBLE SORT) tekniğini kullanıyor. Algoritmanın mantığı içerir. Eğer ardışık iki sayıdan ilki daha büyükse, onların yerleri değiştirilir. Tüm sayılar bu şekilde yukarıdan aşağı doğru tarandığı zaman en alttaki sayı en büyük sayı olur. Eğer tarama aşağıdan yukarı doğru yapılırsa (ki Tablo 2'de bu sistem kullanılmış) en üstteki sayı en küçük sayı olur. Tüm diziyi sıralamak istediğimize göre, bu işlemi tüm sayılar için tek tek yapmalıyız. Ama en üstteki sayının en küçük sayı olduğunu bildiğimize okursanız) bu kuralların sebebini daha kolay anlayacaksınız. Dizinin ilk eleman olması, diziler arasında doğru olanını bulmaya çalışmak gibi zahmetli(!) bir işten kurtaracaktır bizi. Tek boyutlu bir dizi kullandığımızda, elemanların yerini bulmaya çalışmak gibi işlerle uğraşmayız, çünkü ardışık iki eleman arasında beş bayt bulunduğunu biliriz. Son şık basit bir kontrolü daha yapmaktan kurtarıyor bizi. Eğer sıralanacak dizi tam sayı ya da string'lerden oluşuyorsa değişik yapıları test etmemiz gerekecekti, ki bu da daha uzun bir program oluşturacaktı. Tabii ki daha kapsamlı bir program daha çok işinize yarayacaktır. Fakat bu yazıya ayrılan sayfaların sayısı bu kadar detaylı bir çalışmaya izin vermiyor.

En iyisi, lafı daha fazla uzatmamak. Programın assembler listesini Tablo 3'de görebileceğiniz için detaylı olarak buraya yazmayacağım. Program MDE listesini döküm

-
- $57
« $59
- $5B
« $BBA2
$BCSB
ARRTAB
4802
uzunluğunu ekle
ş;N pointeri dizi
göstersin.
(ARRTAB) ,Y
»
NPNT*1
KPNT
45805
NPRT

sonunun beş eksiği son elemanın adresini verir. Lı ARRTAB

Li
BE

41 pointer'ı dizinin ilk elemanını göstersin )

KA
>»
ğ

temizle

BAR
bel
>
35
STA
TAY iyüksek değerlikli Y'ye
'TXA şdüşük değerlikli A'ya
FAC'a
maya kalkarsanız, ilk baştaki doksan değe-
rin sıfır olduğunuz ve sonraki sayıların (eğer
sayılarınızın hepsi pozitifse) sizin dizinizin
sıralanmış hali olduğunu görürsünüz. Bu
yüzden, DIM kullanmadan açılan dizilerde
(eğer eleman sayısı 10'dan azsa DIM komu-
LDA JPNT
JSR COMPARE ile FAC'ı karşılaştır
BM büyük ise dallar
LOY büyük
STY FLAG #Flagsd
SWAP LDA (JPNT),Y
TAX
LDA (JPRTİ),Y
ile
TXA
STA (JPNT1),Y
BPL SWAP
NOSWAP LDA
SEC
sac 4505
STA JPNT
BC$ TESTİ
DEC
TESTİ CMP I1PNT
BNE — JDÖNGÜSÜ
LOA
CHP
BNE
LDA FLAĞ
BEO BİTİR şEvet.
LDA IPNT
ADC
STA IPNT
BOC TESTİ
ENC
TESTİ CMP
BNE — İDÖNGÜSÜ
LDA
CMP #İ-N?
BNE ;Hayır.
BİTİR RTS şEvet.
FLAG *BYTEO
NPNT

Tablo-3: Sıralama işlemini makine dilinde yapacak olan programın assembly listesi.

Bu program A(N) dizisini deminki BASIC program kadar iyi sıralar. Peki BASIC'den kolayca yazmak dururken neden bu karmaşık makine dili rutinleriyle boğuştuk? Bu sorunun cevabını yer alan ufak hız karşılaştırması gösterecektir. Makine dili rutinini yükledikten sonra kalacak yerlere SYS 828'leri koymanız gereklidir. Ama demin olması gerektiğini söyleyerek sıralanmayacaktır. Eğer 100'lük bir dizinin on elemanını doldurup bunu sıralatmanıza ihtiyacınız yoktur. Programın en başında kullanacağınız bir A(5) 53 komutu A için 10'luk bir dizi açacaktır.) 10'dan az eleman kullandığınızda doğru sonucu elde edemezsiniz. Tablo 4'de de gördüğünüz gibi makine dili programımız dizi boyutu büyüdükçe daha fazla zaman kazanmanızı sağlıyor. Eğer bu program bile size yavaş geliyorsa (çok büyük dizileri sıralamak için), daha etkin sıralama algoritmaları kullanmalısınız. Geçen sayılarımızda Sinan sıralamalar konusuna değinmişti. O yazıdan Quick sort algoritmasının mantığını öğrenebilirsiniz. Eğer makine dilinde kendinize gerçekten güveniyorsanız quick sort'u yapmayı bir deneyin. Gerçekten de kendi yığıt'ınızı (stack'inizi) oluşturmanız ve belli sayıları bu yığıta mantıklı bir şekilde atmanız gerekecek. Bu yüzden bu algoritmanın makine diliyle gerçekleştirilmesi oldukça (oldukçadan daha fazla) zordur. Biraz alıştırma yapmak isterseniz, burada yayınlanan sort programını adam etmeyi deneyin. Mesela gerekli kontrolleri yaparak herhangi bir kayan noktalı diziyi sıralamasını sağlayın (sadece ilk diziyi değil). Ya da tam sayı ve string'leri de sıralayabilen genel bir sıralama programı yazın. Tabii her zaman söyledim, söyleye söyleye dilimi kafamdan daha tüylü hale getirdim lafımı tekrarlayacağım: Yaptığınız programları bana da yollayın. Gerçekten de yazılarımın ne derecede işe yaradığını merak ediyorum. Kendi çalışmalarınızda kullanabilmeniz için sık kullanılan ROM rutinlerinin adreslerini Tablo 5'de bir araya getirdik. FAC kolonunda bulunan bir * işareti, FAC'ın içeriğinin değişeceğini, işareti ise aynı kalacağını belirtir. Eğer fonksiyon hem FAC'ı hem de ARG'ı kullanıyorsa rutin çağrılmadan önce A register'ı, yani akümülatör, FAC'ın üssüyle ($61) yüklenmelidir. AND, OR ve NOT gibi mantık işlemlerinde ilk olarak değerler 16 bit tamsayılara çevrilir, daha sonra bitler üzerinden gerekli işlem yapılır ve sonuç tekrar kesirli sisteme döndürülür. BASIC yorumlayıcısının işlemleri yaparken kullandığı bazı sabitler de ROM'da yer alır. Bu sabitlerin değerlerini, anlamlarını ve adreslerini de Tablo 6'da görebilirsiniz. Bu değerler matematiksel işlemleri yaparken sık sık karşınıza çıkacaktır.

Evet, son yazımız da buraya kadar. Aslında işe ilk başladığımda çok daha derinlere inmeyi düşünüyordum, ama daha önce de belirttiğim sebeplerden dolayı bir süre aşırı teknik yazılardan kaçınacak, daha çok yeni başlayanlara yönelik makine diline başlangıç yazılarına yer vereceğiz dergimizde. Bu sayede burada ele alacağımız konulardan daha fazla yararlanabileceksiniz. Eğer Commodore 64'ünüzün tüm ROM'unun makine dili listesini elde etmek istiyorsanız dergimize yazın. Bu konuda size verebileceğimiz çok güzel bir kitap var. İngilizce açıklamalarıyla birlikte tüm BASIC ROM ve KERNAL programları bu kitapta yer alıyor. Yeni bölümlerde buluşmak üzere hepiniz hoşçakalın.

N BASIC Program Makine Dili Rutin 10 0.0" 50 24" 0.4" 100 37" 1.5" 200 6' 6.3" 500 41/ 38.7" 1000 2s 44' 2' 33.4" Tablo-4: Makine dili rutin ile BASIC programın N boyutlu bir diziyi sıralama süreleri.

Adres Sabitin Adresi Hazırlık FAC İşlev $BABC A/Y ARG - sabit $BBEC - FAC « ARG $BB12 FAC « ARG/FAC A/Y FAC « sabit/FAC $BAE2 - FAC - FAC*10 $BAFE - FAC — FAC/10 , $B849 FAC FAC*0.5 $BBA2 FAC sabit ARG « FAC $BBD4 sabit - FAC $B853 FAC « ARG-FAC $B850 FAC « sabit-FAC FAC - ARG*FAC $BA2B FAC « FAC — FAC - sabit*FAC $BF7B FAC —« ARG“FAC $BF78 FAC — ARG“sabit FAC polinom $B043 FAC « polinom2 $AFE6 FAC « ARG OR FAC $AFE9 FAC — ARG AND FAC $AED4 FAC NOT FAC $BC5B FAC ile sabiti karşılaştır $BC1B - FAC'ı yuvarla $BEFB4A - - FAC -FAC Tablo-5: ROM'da bulunan önemli rutinlerin adresleri. Geçen sayıda birlikte tüm fonksiyonları göstermiş oluyoruz. Tabloda gösterilen A, X ve Y harfleri register adlarıdır. FAC ve ARG de daha önce bahsettiğimiz adreslerde ($61.. , $69..) yer alırlar, * ğ Db 4 4 b 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 1

- - -

DEĞERİ 3.14159265 -32768 1 *434255942 2.88539007 *707106781 1/SOR(2) 1.41421356 SOR(2) -.5 :693147181 LOG(2) 10 99999999.9 999999999 1E9 1.44269504 1/106(2) 2.14987637E-5

$BFE8 00 00 00 1
35 44 TA 11879546
$E092 28 BI 46 3.92767774E-Â
$E2EO 49 OF DA 1.57079633
$E2E5S 49 OF DA 6.28318531
$EZ2EA 00 00 00 00 :25
$E2FO EĞ 1A 2D
$E2FS 28 07 FB F8 42.0077971
$E2FA 99 68 89 Ol — -76.7041703
$E2FF 23 35 DF El 81.6052237
$E304 AS 5D E? 28 — -41.3147021
$E309 49 OP DA A2 6.28318531
$E33F B3 83 BD D3 — -6.84793912E-4
$E344 1E F4 AĞ F5 4.85094216E-3
$E349 83 FC BO 10 -.0161117015
$E34E OC 1F 67 CA
$E353 DE 53 CB  -.054279133
$E358 14 64 70 4C .0724571965
$E35D B7 EA 51 TA  -.0898019185 1.4352314E-4
$E362 63 30 88 TE *110932413 1.34226348E£-3
$E367 92 44 99 TA 1D 84 1C
$E36C 4Cc cc 91 c7 «19999912 7C 63 59 58 «0555051269
$E371 AA AA AR 13 — -.33333316 TE 75 FD EE? .240226385
$E376 00 00 00 00 1 80 31 72 18 10 .693147186

Tablo-6: Bellekte yer alan sabitler, değerleri ve çok önemlilerinin anlamları. Eğer yapacağınız işlemlerde bu sabitler gerekiyorsa, değeri programınıza eklemenize gerek yok. ROM'unuzu kullanıverin.