ROM'unuzdan Yararlanın - 3

Neredeyse iki aydır “ROM rutinlerini açıklayacağım” deyip deyip teorik bilgileri sıralıyordum. Ama emin olun bütün teorik bilgiler birazdan vermeye başlayacağım rutinlerin ne olduğunu anlamanıza yardım edecek. Eğer doğrudan rutinlere kalkışsaydım, herkesin kafasında koca koca soru işaretleri kalacaktı (dediğimde bunun Floating Point Accumulator'u! -Bir Ayan Nokta Değişkeni diyebiliriz mesela- olduğunu kaçınız tahmin edebilirdiniz?). Teorik bilgilerle sizi neden sıktığımı da anlatıp içimi rahatlattıktan sonra, bu ay neleri anlatacağımı kısaca özetleyeyim: Hepinizin makine dilinde çarpma, bölme, sinüs alma vb. işlemlerini yapmak için öldüğünüzü biliyorum, ama canınızı biraz daha sıkabilmek için ilk olarak sayıları değişik tam sayı formatlarından kesirli sayılara çeviren rutinlere değinmek istiyorum. Bu konu gerçekten de önemli sayılabilir, çünkü program hızlandırmak istediğiniz her yerde basit işlemleri ROM'a yaptırmak yerine kendiniz yapmak zorunda kalırsınız. Bu işlemleri de tam sayılar üzerinden yapmak çok daha kolaydır. İsterseniz size daha somut bir örnek vereyim: Diyelim ki, bir ile yüz arasında değişen tam sayıların ortalamasını alacak bir program yapacaksınız. İlk olarak kullanıcıdan aldığınız tüm sayıları birer baytlık tam sayı olarak saklarsınız. Sonra bunları basit ADC komutlarıyla iki baytlık bir yerde toplarsınız. Daha sonra bu sayıları birazdan vereceğim ROM rutinlerinden uygun olanıyla ikilik kesirli sayıya çevirirsiniz ve son olarak da -umarım bu ay verebileceğim- bölme rutiniyle girilen sayı miktarına bölersiniz. Bu sayede yapacağınız ortalama alma işlemi, kesirli sayılarla yapılandan hem daha hızlı olacaktır, hem de daha az bellek işgal edecektir.

Bu rutinleri bilmenin gerekliliğine ikna olduğunuza göre, adresleri vermeye başlayabilirim: Tam Sayıdan Kesirli Sayılara Geçiş

1. İşaretli bir bayt sayı - $BC3C: Aşağıdaki rutin bir baytlık işaretli bir sayıyı (-128..+127) kesirli sayıya çevirir. Negatif değerler -geçen sayıda da bahsettiğim gibi- A'da (akümülatörde) bulunan pozitif sayıya:

CLC ADC #$0L komutlarının uygulanmasıyla elde edilir. Sayının mutlak değeri de aynı işlemler sonucu bulunabilir. Aşağıdaki rutini çağırdığınızda sonucu FAC'a yerleştirirsiniz:

LDA (-127..128)
SR $BC3C

A'da bulunan $80 -128'e, $FF -1'e, $7F +127'ye çevrilecektir. 2. İşaretsiz bir bayt sayı - $B3A2: Eğer baytın işareti yoksa, değeri 0-255 arasındaysa bu rutin kullanılır. Bu rutinde dikkat etmeniz gereken şey, baytı A'yla (akümülatörle) değil Y registeriyle iletmeniz:

LDY Hsayı (0..255)
JSR $B3A2

Sonuçta $00 0'a, $80 128'e, $FF 255'e çevrilir. 3. İşaretli iki bayt sayı - $B395: İşaretini de bulunduran iki baytlık bir sayı (-32768..+32767) aşağıdaki basit rutin kullanılarak yerleştirilir: LDY #Alçak LDA #Yüksek JSR $B395

Bu rutinde de alçak ve yüksek baytın yerini karıştırmamaya bakın. Eğer 32767'yi çevirecekseniz:

32767 -$TFFF,
LDY HSFF
LDA
JSR $B395

rutini kullanın. Y'de hep düşük değerlilik (alçak bayt) bulunmalıdır. Aşağıdaki sayılar sanırım konuyu tam olarak anlamanıza yardımcı olacaktır.

A Y Sonuç 00 00 0 00 01 1 00 FF +255 01 00 +256 7F FE +32767 80 00 -32768 FF FF -1 4. İşaretsiz iki bayt sayı - $BC49: Eğer iki baytlık sayınız her zaman pozitif değerler alacaksa aşağıdaki rutini kullanmalısınız. Yalnız bu rutinlere biraz dikkat edin, gittikçe karmaşıklaşıyor çünkü

LDY
LDA gYüksek
STY $63
STA $62
LDX
SEC
JSR $BC49

Bu rutin, sayınızın hep pozitif olduğunu varsayarak 0..65535 arasında bir sayı yerleştirir. İsterseniz A ve Y'ye verilen tipik değerler sonucunda ne sonuçlar alacağımıza bir göz atalım:

A Y Sonuç 00 00 0 00 01 1 00 FF +255 01 00 +256 7F FE +32767 80 00 +32768 FF FF +65535

5. İşaretli üç bayt sayı - $BC4F: Her ne kadar bu kadar yüksek değerli sayılar pek kullanılmasa da ROM'da bulunan tüm tam sayı-kesirli sayı çevrimlerini ele almak için bu rutine de değineceğim: LDA #Düşük LDX #Orta LDY #Yüksek STY $62 STX $63 STA $64

Böylece aşağıdaki çevrim tablosunu elde ederiz:

S6) SES
v0 00 00
v0 00 00 FE

SAT 109) 09)

6. İşaretsiz dört bayt sayı - $BC4F: Son olarak da işaretsiz dört baytlık sayıları inceleyeceğiz. Bu çevrimi yapmak için de aynı rutini kullanıyoruz ve baytları $62-$65 arasına yerleştiriyoruz. Tek fark olarak bu sefer hep Carry (elde) = 1 yani pozitif sayılar gönderiyoruz:

SEC
LDA «800
LDX
JSR $BC4F

Bu sayede 0 ile 2^32-1 = 4,294,967,295 arasındaki tüm tam sayılarla işlem yapılabilir: Dikkat ettiyseniz maksimum kesinlikten fazla bir kesinlik istediğimiz için 0 ile $80000000 arasında bir fark göremiyoruz. “Yukarıdaki rutinleri ezberlemeniz gerek?” diye bir şey söylemiyorum. Neler yapılabildiğini bilin ve ihtiyacınız olursa burada olduğu gibi kullanın. Özellikle son ikisine ihtiyacınız olacağını hiç sanmıyorum. Ama dört rutini sıkça kullanabilirsiniz. Kullanacağınız registerleri karıştırmamaya kesin özen gösterin. Çünkü rutinlerde bir standart yok. Kimi zaman A yüksek değerlikli baytı almış, kimi zaman Y. Bu tür hataları farketmek de çok çok zor olduğu için rutinleri kullanırken registerlere hangi değerleri verdiğinize mutlaka özen gösterin. Bu sayıda yine pek yer bırakmadım. Ama isterseniz bir de kesirli sayılardan tam sayılara geçişe göz atalım ve “Bu aylık da bu kadar?” diyelim: 0 00 00 FF 00 7F 7F FF +2,147,483,647 (2.1474836E+09) 80 00 00 00 -2,147,483,648 (-2.1474836E+09)

Kesirli Sayılardan Tam Sayılara Geçiş Bu ters çevrim diğerine göre oldukça kolay, çünkü tek bir rutini öğrenmeniz gerekli. Sonuç işaretli bir dört bayt sayıdır ve $62-$65'te tutulur. Eğer çevrilecek sayı FAC'daysa (yani şu komutla tam sayıya çevrim yapılır: JSR $BC9B

00

Sadece 2^31'den küçük sayılar hatasız çevrilebilir, bu yüzden üssün değerinin $A0'dan küçük olup olmadığını kontrol etmeyi sakın unutmayın. Çevrimin sonucu $62 (MSB, işaret bitini de içerir) ile $65 arasında yer alır. İsterseniz bir iki örnek üzerinde uğraşalım:

FAC'da $0A (-10) bulunsun:

Üs M1 M2 M3 M4 İşaret 84 A0 00 00 00 00 JSR sonrasında şunu elde ederiz: $0061 84 00 00 00 CA 00

Eğer FAC'da tüm sayı tutulmuyorsa, kesirli kısım INT fonksiyonunda olduğu gibi atılacaktır. 321.25'te bu işlemi bir deneyelim isterseniz:

Üs M1 M2 M3 M4 İşaret 89 A0 A0 00 00 00

Sonuçta şunu görürüz: $0062 89 00 00 01 41 00

Daha açıkçası $41 4 $0100 = 321. Eğer eksi kesirli sayılar kullanırsanız bir küçük tam sayıya yuvarlanır: INT (-0.5) = -1:

Üs M1 M2 M3 M4 İşaret $0061 80 80 00 00 00 FE

Sonuç olarak:

$0061 89 FF FF FF FF FE yani -1 elde ederiz. Daha ilerde yorumcusunun sınır değeri kontrol eden rutinleriyle de tanışacağız (0..255 ya da -32768..32767 gibi). Şimdilik temel çevrim rutinlerinin tamamından biraz bahsettik. Bu ay bir de kısa programımız var. Dergimizin sürekli takipçileri, Atölye yazısında bahsettiğimiz ondalıkçı adlı rutini hatırlarlar. İki baytlık bir sayıyı (işaretsiz tabii ki) ASCII kodlarına çevirebiliyordu bu rutin. Ama oldukça da uğraştırıcıydı. Şimdi size ROM kullansaydık ne kadar rahat edeceğimizi göstereceğim:

Gördünüz mü ne kadar kolay oldu? Sadece sayıyı kesirli formata çevirdik, $BDDD'ye sıçradık ve sonucu ekrana yazdık. Bu işi daha kolay halledebilecek olan varsa beri gelsin... Bu aylık da bu kadar, gelecek ayın yazısında rutinlerinin arasına iyice dalacağız. Şimdilik hoşçakalın.