ROM'unuzdan Yararlanın
Retro bilgisayarYararlanın
sayıda makine dilinin daha kolay kullanma yollarını araştırıyorduk hatırlarsanız.
Ama daha işin başından zorlu bir kayaya çarptık. Makine dilini kullanarak ondalıklı sayılarla işlemleri nasıl yapacağımız sorununu araştırmak istiyorduk. Ama bu işe girişmeden önce sahip olmanızı istediğim temel birazcık uzun sürecek gibi. En iyisi lafı fazla dolandırmadan temeli inşa etmeye devam edelim, yoksa bu sayı da harcanacak gibi... Hatırlarsanız geçen sayıda ikilik düzende ondalık kesirli sayıları nasıl ifade edebileceğinizi anlatmıştım. Son olarak da birkaç örnek çözmüştük. Bu sayıda da kaldığımız yerden devam edeceğiz. İlk olarak düzendeki kesirli sayıların ondalık düzendeki karşılığını bulmayı öğreneceğiz, daha sonra bu sayıların bilgisayarda kullanılmasıyla ilgili birkaç örnekle uğraşacağız. Kolay gelsin! Geçen sayıdaki bilgilerimizle sayıları ondalık düzenlerden ikilik düzene çevirebiliyorduk. Şimdi de tersini yapmaya çalışalım. Hatta anlamak için örnek üzerinde çalışalım. Örneğimiz geçen sayıda çözdüğümüz -5.5 olsun: ÜS M1 M2 M3 M4
M3 M4
83 BO 00 0000 sonücünü geçen sayıda bulmuştuk. Geri dönmek için uzun uzun uğraşmak yerine basit bir formül oluşturalım isterseniz: SAYI — (ML AND 128)*2.(ÜS-129)* AND ( işareti üs alma işlemini gösteriyor.) Yukarıdaki formüle dikkatle baktığınızda işaretin doğrudan doğruya Mantisa'nın ilk baytının (M1) son bitinden okunduğunu
Vedat Hallaç
0. -0.0078125 -0.0009765625 0.0005859375
-0.00048828125
-0.00009765625 - -0.00006103515625
0.00003662109275
İkinin üssü: -2 görebilirsiniz. Üssü hesaplamak için üs baytının 129 eksiğini almamıza da dikkatinizi çekerim. Bir de, her bitin etkisini ayrı ayrı hesaplamak yerine baytların değerini olduğu gibi 256'ya (ve katlarına) bölerek bit ağırlığı hesaplaması yapılıyor. İsterseniz formülümüzü yukarıdaki sayı üzerinde deneyelim: X = -SGN(176 AND 128) Bu işlem sonucunda orijinal -5.5 sayısını elde ederiz. İsterseniz bu konuyu pekiştirmek açısından siz de bazı sayıları ondalık düzenden ikilik düzene çevirin, sonra da aynı işlemi tersine yapın. Bilirsiniz, pratik olmadığı zaman bu teorik bilgiler uçup gider... Hayat o kadar da kolay değil... Şimdiye kadar çözdüğümüz tüm örneklerde ikilik düzendeki sonuçlar tam olarak bitlerine sığdılar. Oysa gerçek hayatta her şey bu kadar basit değildir. İsterseniz bir de 0.4'ü ikilik düzene çevirmeye Geçen sayıda yaptığımız gibi her seferinde ikinin en yüksek üssünü sayımızdan çıkararak ilerleyeceğiz: Bu işlemleri sonsuza kadar sürdürebiliriz.
nun
Bölmelerin sonucu hiçbir zaman sıfıra erişmeyecektir. Sonuç olarak kendini tekrar eden bir sayıyla karşılaşırız:
1001 1001 1001 1001 1001 1001 1001 Bu da demektir ki 0.4 sayısı ikilik düzende hiçbir zaman tam olarak ifade edilemez. Elimizde 32 bit olduğu için ilerlemeyi 31. bitte durdurmamız gerekir. Yani sonuç olarak:
1.1001 1001 1001 1001 1001 1001 1001 1001 değerini alacaktır. Üs ve işaret bitiyle birlikte: 0100 1100 1100 1100 1100 1100 1100 1100 veya onaltılık olarak: 3F4CCCCCCD değerini alacaktır. 0.4'ü bu düzeyde yazamamış olmamız kesinlikle sadece ikilik düzeyden doğan bir problem değildir. Aynı problem her düzeyde bulunur. İsterseniz 1/3'ü ondalık düzende yazmaya çalışın. Sonuçta şöyle bir
Ve bu sayıyı da bir yerlerde kesmek zorunda kalırsınız. Oysa onluk düzende bu sayı 0.333... olarak ifade edilir.
Yaşasın, pratiğe geldi sıra: Satırlar dolusu karmakarışık teorik bilgiler sonucunda öğrendiğimiz bu ikilik-onluk, onluk-ikilik dönüşümleri ve kesirli sayılarla yapılan işlemler bilgisayar tarafından sık sık kullanılmaktadır. Bu yüzden BASIC-ROM'da yerlerini almış durumda beklerler. Bu durumda yapılacak en iyi şey bu rutinleri kullanmayı öğrenmek olacaktır sanırım. BASIC yorumcusu işlemleri için iki adet kesirli sayı belleğine sahiptir. FAC (Floating Point Accumulator) adını alan bu belleklere sırasıyla FACHI ve FACR2 isimleri verilir. Her iki akümülatör de 6'şar bayttan oluşur (1 bayt üs için, 4 bayt mantisa için, 1 bayt da işaret için). Bu baytların yanında, bazı işlemler için kullanılabilecek ekstra iki bayt daha vardır. Tek girdili işlemler yapılacaksa (SIN, COS, LOG, vb. gibi) mutlaka FACHI kullanılır. Eğer toplama, çarpma gibi işlemler yapılacaksa ikinci sayıyla karşılaşacaksınız: değer FACR2'de kullanılır. İşlemin sonucu ise her zaman FAC'de tutulur. Bu sebeple genelde FAC, FACR2 ise ARG (argüman) olarak kullanılır. Bu sayede önceliği daha iyi vurgulanır. C64'LE İLGİLİ ÇARŞAMBA GÜNLERİ
HER ŞEY UCUZ
Bu akümülatörlerdeki sayılar sıkıştırılmış 5-bayt formatında tutulmazlar. İşaret bitini tutmak için bir bayt ayrılmıştır. Demin söylediğim ekstra baytlardan biri yuvarlama işlemleri için kullanılan genel bir bayttır (yuvarlama baytı). Diğeri ise iki girdili işlemlerde, işaretlerin karşılaştırılmalarının sonucunu tutar. Eğer iki girdinin de işareti aynıysa $00, farklıysa $FF değerini alır ve işaret karşılaştırma baytı olarak adlandırılır. Bu baytların adreslerini aşağıdaki tabloda bulabilirsiniz.
Tablo 1: ROM tarafından kullanılan adresler.
Commodore BASIC işlemcisinin kesirli sayıları ilgilendiren oldukça fazla rutini vardır. Biz en basitinden, yani ondalık düzende bulunan bir sayıyı ikilik düzene çeviren rutine göz atacağız. İlk olarak. Ama bundan önce, Commodore'un sizle iletişim kurmasını sağlayan en önemli rutinine bir göz atmamız yerinde olur. Çünkü bu rutini sık sık kullanacağız. Bu rutin sıfırıncı sayfada yer alır ve CHRGET sembolik ismiyle tanınır. CHRGET'in yaptığı tek iş, kendisine her sıçranıldığında sırada duran klavyeden ilkini alıp size iletmektir. Ama bu işi yaparken bazı karakterler göz ardı edilir, bazıları da değişik anlamlar taşırlar. Rutine sıçranılabilecek bir adres daha vardır. CHRGOT adıyla tanınan bu adres, CHRGET ile son alınan baytı size tekrar iletir.
Bu rutinin en esnek yanı (ve RAM'de yer almasının sebebi) kendisini değiştiren bir rutin olmasıdır. Yani her baytı aldığınızda, kendi içinde bulunan bir vektörün (TXTPTR) gösterdiği adres bir artırılır. TXTPTR, okunacak bir sonraki harfin bellekteki adresini tutar. Eğer rutinin bellekteki halini incelerseniz olayı daha iyi kavrarsınız:
Cmp
Bes
Cmp
Beg
Sec
Sbe
Sec
Bitir
CHRGET rutinine her sıçrayışınızda, CHRGOT'da ($0079) bulunan adres bir artırılır, bu adresteki değer alınır ve gerekli karşılaştırmalar yapılır. Eğer alınan geçerli bir harfse (kodu $3A'dan büyükse), harf A registerinde (akümülatörde) tutularak geri dönülür. Kodu $3A'dan küçükse, ilk olarak harfin boşluk olup olmadığı kontrol edilir. Eğer boşluksa, bir sonraki harf alınır. Yani BASIC, komutlar arasındaki boşlukları hiçbir zaman görmez. Eğer harf bir boşluk değilse yapılan çıkartma işlemlerinin akümülatör üzerinde hiçbir etkisi olmaz. Yalnızca elde bayrağı (carry flag) alınan harfe göre değer alır: Harf “0” ile “9” arasında bir rakamsa (kodu $30-$39 arasındaysa) elde bayrağı sıfır olur. Eğer son alınan harf iki nokta üstüste (“:”) ise geri dönüşte sıfır bayrağı da kaldırılır. Kısaca özetlersek: CHRGET rutini ilk olarak alınacak harfin yerini gösteren TXTPTR'nin değerini bir artırır ve alınan karakteri akümülatöre koyarak geri döner. Eğer bu karakter iki nokta üstüste ($3A) ise, ya da $00 ise sıfır bayrağı kaldırılır. $3A komut sonunu, $00 da satır sonunu belirtir. Eğer bir rakam okunduysa elde bayrağı temizlenir. Artık ondalık düzendeki kesirli sayıları ikilik sisteme çevirecek rutini inceleyebiliriz. $BCF3 adresinde bulunan bu rutin, ASC-FLOAT adıyla tanınır. Bu rutini çağırdığınızda A'dan ilk rakam (veya işareti) bulunmalı ve bayraklar CHRGET'in ayarladığı şekilde durmalıdır. Doğal olarak TXTPTR'de sayının ASCII kodları bulunmalıdır.
-CHRGET rutininin bellekteki durumu.
88388888
bir sayıyı okuyarak ikilik kesirli sayılara çevirebilirsiniz: Programı kullanmak için SUPER ASSEMBLER'ı yükleyin ve çalıştırın. Daha sonra bir de monitör programı ($8000'de veya $C000'da çalışması iyi olur) yükleyin. Şimdi programı yazın, kasede veya diske kaydedin, RUN ile belleğe assemble edin. Daha sonra monitör programını çalıştırın.
D 033C
komutunu kullanarak programı görebilirsiniz. Sayınızın ASCII kodları $034B adresinde bulunur ve sonunda bulunan $00, sayının nerede bittiğini gösterir. Şimdi programı “G 033C” komutunu kullanarak çağırın. 1.2345 sayısının mantisa ve üs değerlerini tabloda bulunan adreslere bakarak rahatça görebilirsiniz:
M 0061 0066
30061 81 YE 04 18 93 00
İsterseniz bir de bildiğimiz 0.4'ü deneyelim. Değişik sayılar vermek için $034B adresinde bulunan rakamları değiştirmeniz gerekir:
M 034B
32 2E 32 33 34 35
sayıyı 30 2E 34 00 00 00 00 00 yapın. Programınızı şimdi çağırırsanız $0061'de 0.4'ün ikilik düzendeki karşılığını görebilirsiniz. Bu sonuç:
30061 7F CC CC CC CC 00
olacaktır. Sayının işareti ayrıca bir baytta tutulacaktır (altıncı bayt). Bu rutine yolladığınız sayıların başına +, - koyabilirsiniz. Ayrıca sayının içinde “on üzeri” anlamına gelen e karakterini kullanabilirsiniz. Yani -1000 yerine “-1e3”, ya da -0.001 yerine “1e-3” kullanabilirsiniz. ROM'unuz bu gösterimi rahatlıkla anlayacaktır. İsterseniz şimdi bir de “-1E8” sayısını çevirelim. Sonuç olarak: 30061 9B BE BC 20 00 FF elde edeceksiniz.
Sanırım buraya kadar yaptıklarımızın kullanımını iyice öğrenmişsinizdir artık. İsterseniz birkaç örnek sayı bulup bunları elle hesaplayın, daha sonra yukarıdaki rutini kullanarak sonuçlarınızı test edin. Bunun oldukça yararı olacaktır. Şimdi tekrar 0.4 örneğimize dönelim. Sanırım çoğunuz 0.4'ü ikilik düzene çevirdiğimizde yuvarlanmamış olduğunu fark etmişsinizdir. Yani bu rutini kullandığınızda yuvarlama işlemi otomatik olarak yapılmaz. Ama bu konuda gereken bilgiler gene de size iletilecektir. Tablo 1'de gerekli baytları açıklarken bir de yuvarlama baytından bahsetmiştim. Bu bayt işte burada işimize yarayacak... Şimdi 0.4 örneğini tekrar çalıştırın ve $0070 adresindeki değere bir göz atın. Burada $80 değerini göreceksiniz. Bu değer sonucun tam olarak bitmediğini ve son biti bir artırmanızı söyler size. Tabii ki bu işle de sizin ilgilenmeniz gerekmez ROM'da bu baytı kontrol eden ve gerekli durumda sayının son bitini bir artıran bir rutin mevcuttur. Deminki programı, yuvarlama işlemini de yapacak şekilde değiştirmek için aşağıdaki satırları programınıza ekleyin ve tekrar assemble edin. -.EQ ROUND-SBC1B 105 Program 2: Sayıyı yuvarlamak için programa eklemeniz gereken satırlar.
Bu programda 0.4 örneğini denediğimizde şu sonucu elde ederiz:
30061 TF CC CD 00
Gördüğünüz gibi sayı otomatik olarak yuvarlandı. Merak edenler için söyleyeyim, yuvarlama rutini bu işi yaparken yuvarlama baytını da temizler. Yani, hiçbir zaman yuvarlanmış bir sayının son bitinin tekrar artırılması söz konusu olmaz. Nasıl? Sayıları ikilik düzene çevirmek pek de zor değil, değil mi? Emin olun bu işin tersini yaptırmak daha da kolay. Tüm yapmanız gereken ikilik düzendeki bir sayıyı $0061'e yerleştirmek ve $BDDD adresinde bulunan FLOATASC adlı rutine sıçramak. Bütün işlemler bilgisayarınız tarafından gerçekleştirilecektir. Sonucu nasıl mı göreceğiz? $0100'a bir göz atarsanız sonucun ASCII değerlerini burada görebilirsiniz. İsterseniz bu konuda da biraz örnek çizelim:
30061 90 8F 00 00 00 80 girip $BDDD'ye sıçrayın (JSR $BDDD; BRK komutlarını monitörden kullanarak). Şimdi $0100'da yazılı olanlara bir bakalım:
30100 2D 33 36 36 30 38 00 00
Bu sonucu kullanıcıya kolayca iletebilmemiz için en sona $00 bile eklenmiş. Bütün yapmamız gereken Y, A'ya $0100 verip $AB1E'ye sıçramak. Bir sayıyı ikilik düzenden ASCII formatına çeviren ve bunu ekrana basan programcığı aşağıda bulabilirsiniz:
Bu programla ikilik düzenden ASCII'ye çevirdiklerinizi kolayca ekrana basabilirsiniz.
Aylık da yerimiz buraya kadar izin veriyor. Gelecek ay, ROM'da bulunan değişik rutinlerden bazılarının kullanılışını açıklamak istiyorum. Eğer yerimiz kalırsa basit matematik işlemlerinin adreslerini öğrenmeye de başlayabiliriz. Gelecek ay görüşene dek hoşçakalın. Commodore