ASSEMBLER-2

İnsan beyninin bilgisayarlara göre en önemli üstünlüğü birkaç işlemi aynı anda yapabilmesidir. Örneğin bir insan müzik dinlerken kitap okuyabilir ve aynı zamanda bir şeyler yiyebilir. Bilgisayarlarda ise durum tamamen farklıdır ve tüm işlemler belli bir sıraya göre ardı ardına yapılır. Yalnız burada her şey o kadar hızlı gerçekleşir ki bilgisayar aynı anda birden fazla işlem yapıyormuş gibi görünür. Makine dilinin mantığı da hemen hemen aynıdır. Assembler komutlarını bilgisayar çok yakından tanıdığı için bunları hemen işleme koymaktadır. Böylelikle makine dilinin özelliklerini mantıklı şekilde kullanarak bilgisayarımızın birkaç işi birden yapmasını sağlayabiliriz. Yukarıda bahsettiğimiz komutlar zincirinin ilk parçası LDA komutudur. Bunun anlamı şudur: Bellekteki değeri akümülatöre yükle (Load accumulator with memory). Tüm Assembler komutları üç harften oluşmaktadır. Geçen sayımızda her makine dili komutuna bir 8-Bit kodun eşlenmiş olduğunu belirtmiştik. LDA komutu için bu kod $A9 veya desimal 169'dur (ikilik sistemde de 10101001). Şimdi bu kodun belleğin herhangi bir baytında kayıtlı olması lazımdır. Bu bayt $1500 veya desimal 5376 olsun. O halde Assembler satırımız şu şekilde olmalıdır:

1500 LDA

Yalnız burada yine eksik bir şey vardır. Akümülatöre hangi değer yüklenecek? PEEK, POKE gibi bazı Basic komutlarında da olduğu gibi Assembler komutlarının birçoğu da tek başlarına kullanılmazlar. Bunlarda her seferinde komutu takip eden bir parametre bulunur. Makine dilinde bu parametreler ikiye ayrılır: Bir baytlıklar ve iki baytlıklar. Eğer akümülatöre 01 değerini yüklemek istersek Assembler satırımız şu şekli alacaktır:

1500 LDA # $01

Şimdi burada 01 değerinin önündeki # ne işe yarıyor diye soracaksınız. Assembler programlarının birçoğu veri girişinde onaltılık sayı sistemini kullanır, fakat bunun yanında ikilik veya onluk sayı sistemini kullananlar da vardır. Hatta çok gelişmiş bazı Assembler'lar ASCII işaretlerini de kullanırlar. Her veri giriş türü için bir özel sembol belirlenmiştir. Genellikle onaltılık sayı sistemi için “$”, ikilik sayı sistemi için “%”, desimal için “#” kullanılır. Yukarıdaki örnekte kullanılan “#” parametrenin onaltılık sayı sisteminde olduğunu belirtmektedir. “#” işaretine gelelim. Akümülatöre bir değer yüklemenin çok çeşidi vardır: Burada olduğu gibi doğrudan bir sayı verme, herhangi bir adreste bulunan değeri yükleme vs. Bizim kullandığımız doğrudan bir sayıyı akümülatöre yükleme yöntemine “dolaysız adresleme” adı verilir ve “#” ile belirtilir. Eğer $1500 adresinde LDA'nın makine dili karşılığı yer alırsa bir sonraki adreste, yani $1501'de akümülatörün alacağı değer olan 01 bulunmalıdır. Bu nedenle bir sonraki Assembler satırımızı hafızada ancak $1502 adresinden sonra yerleştirebiliriz. Bir Monitör ile Assembler'da program yazarken genellikle istenen başlangıç adresinin başına bir “A” harfi konulur. İlk satır yazılıp RETURN'e basıldığında bilgisayar yazdığımız satırın kaç bayt işgal ettiğini hesaplar ve bir sonraki satırın başlayacağı adresi otomatik olarak yazar. Örneğin EXMON'da şu satırları yazmalısınız:

A 1500 LDA # $01
Şimdi RETURN'e bastığınız ekranda
A 1500 LDA # $01
A 1502

satırları gözükür ve bilgisayar bizden bir sonraki satırı girmemizi bekler. $1502 adresine desimal olarak 0 ile 255 arası değerler yazabiliriz, fakat bu değerlerin herbirinin makine dilinde komut olarak bir karşılığı yoktur ve eğer burada karşılıksız bir değer varsa bilgisayar bunun yorumunu yapamaz ve kilitlenir. Bu nedenle Basic'te olduğu gibi satır numaralarını istediğimiz gibi belirleyemeyiz. Bilgisayar tarafından okunmasını istediğimiz iki satır arasında bir bayt bile boşluk olamaz. Şimdi isterseniz programımıza son verelim. Burada Basic'te oldukça sık kullanılan STOP benzeri bir komut kullanacağız: BRK. Bu komutun diğer işlevlerine daha sonra değineceğiz, fakat şu anda bilmemiz gereken tek unsur bilgisayarın bu komut ile karşılaştığında tüm registerlerin o anki değerlerini ekranda gösterdiğidir.

A 1502 BRK ile programımızı bitirebiliriz. Şimdi hafızada $1500 adresinden başlayan bu ilk programımızı çalıştırmalıyız. Bu iş için birçok monitör programında aşağıdaki satır kullanılır:

1500

Eğer Basic'ten çalıştırmak istersek SYS 5376 yazmalıyız ($1500'ün desimal karşılığı 5376'dır). Yukarıdaki yöntemlerden biriyle programı işlettiğinizde ekrana register tablosu gelecektir. Bu tabloyla daha önce monitör programını ilk kez çalıştırdığımızda karşılaşmıştık. Şimdi registerlerin aldığı değerlere bir bakalım. Akümülatörün değeri 01, program sayacının değeri 1502'dir.

Statüs registerinde ise Break Bit'i dı-
şındaki tüm Bit'ler O'dır.
Programımızda ufak bir değişiklik
yapalım:
A 1500 LDA # $00
A 1502 BRK

Programı tekrar işlettiğimizde program sayacı 1503, akümülatör 00 olacaktır. Statüs registerinde ise “Zero-Flag” yani “sıfır göstergesi” de 1 değerini alacaktır. Şimdi son olarak akümülatöre $FF değerini yükleyelim:

A 1500 LDA # $FF
A 1502 BRK

Programı tekrar çalıştırdığınızda akümülatörün ve program sayacının beklenen değerleri almasına karşılık statüs registerindeki 7. Bit'in 1 değerini alacağını göreceğiz. Bu bit “Negatif Flag” diye adlandırılır ve bir işlemin sonucunun artı veya eksi olup olmadığını gösterir. Peki, akümülatörde $FF veya desimal 255 değeri varsa, neden statüs registeri akümülatörün değerini eksi olarak gösteriyor? Bu bilmecenin çözümü için daha bir süre beklememiz gerekecek. Yalnız burada hemen şunu belirtelim: Eğer bir sayının 7. Bit'i 0 değilse statüs registerindeki Negatif Flag 1 değerini alır. Bu konuya daha sonra negatif ikilik sayıları incelerken değineceğiz. Şimdi statüs registerinin Bit'lerini teker teker ele alalım: NV-BDIZC 76543210

7) N (negatif): Bir önceki işlemler negatif mi? 6) V (overflow): Bir önceki işlemin sonucu 127'den büyük mü? 5) -boş- daima 1 değerini taşır. 4) B (break): Program kesintiye uğramış mı? 3) D (decimal): İşlemci desimal işlem modunda mı? 2) I (interrupt — kesinti): Interrupt durdurulmuş mu? 1) Z (Zero): Bir önceki işlemin sonucu sıfır mı? 0) C (Carry): Bir önceki toplama, çıkarma veya kıyaslama işleminde kalan var mı?

Mutlak adresleme:

STA “Store Accumulator”, yani akümülatördeki değeri belleğe yükle anlamına gelmektedir. Bu komutu kullanarak akümülatördeki değeri ekran belleğinin ilk baytına ($0400) kaydedelim:

A 1500 LDA # $01
A 1502 STA $0400

STA komutu ile yeni bir adresleme yöntemi ile tanışıyoruz: Mutlak Adresleme. Bu adresleme yönteminin başlıca özelliği hafızada iki bayt kullanmasıdır. Yukarıdaki program hafızada şu şekilde yer alır:

1500 LDA
1501 $ 01
1502 STA
1503 $00
1504 $04

ASSEMBLER

KOMUT LDA

LDX LDY STA STX

STY RTS

Adresleme Yöntemi Kodu Etkilediği Gösterge

Dolaysız 2 Mutlak 4 Dolaysız A2 2 Mutlak AE 4 Dolaysız A0 2 Mutlak AC 4 Mutlak 8D 4 Mutlak 8E 4 Mutlak 8C 4 - 60 6

Bu şekilde komutumuz 3 bayt işgal etmektedir ve bir sonraki serbest bellek adresi $1505'dir. Basic ile ilgilenmiş olanlar 01'in A harfinin ekran kodu olduğunu bilirler. Ekranın sol üst köşesinde beliren A harfini istesek başka bir renge de boyayabiliriz. Ekran renk kodları ise C-64'ün belleğinde $D800 adresinden itibaren yer almaktadır. Bunun için programımıza aşağıdaki satırları ekleyelim:

A 1505 LDA # $00
A 1507 STA $ D800

Bundan sonra yazacağımız satır $150A adresinde olmalıdır. Bu sefer programımızı bitirmek için BRK komutunu kullanmayacağız, zira her makine dili programın bitiminde register göstergesiyle karşılaşmak istenilmez. Bunun için yeni bir komut kullanacağız: RTS

RTS “Return from Subroutine” veya alt programdan dönüş anlamına gelmektedir. Bu komut kullanılırken ardında herhangi bir parametre yer almaz. Bilgisayar RTS komutu kullanıldığında gideceği adresi Stack-Pointer'dan öğrenir. Şu satırla programımızı bitirelim:

A ISOA RTS

Monitörden çıkmamışsak G 1500 ile, Basic'e dönmüşsek programı SYS 5376 ile çalıştıralım. Ekranın sağ üst köşesinde siyah bir A harfi gözükecektir.

Bu programı doğrudan Basic kullanarak da yazabiliriz, fakat teker teker her komutun desimal karşılığını hesaplamalıyız. Sonuçta aşağıdaki Basic program ortaya çıkacaktır.

10 FOR TO 5386: READ A:
POKE I,A: NEXT I: END
20 DATA
169,1,141,0,4,169,0,141,0,216,96
Dört yeni komut:

LDA ve STA'nın kombinasyonu Basic'teki POKE komutuna karşılık gelmektedir. Assembler'da bir sayı doğrudan doğruya bir bayta yazılamaz, bu iş için her seferinde akümülatör kullanılmalıdır. Makine dilinde akümülatörle aynı görevi gören iki register vardır: X ve Y registerleri. Bunlar için ayrıca LDX (X registerini yükle), STX (X registerini boşalt), LDY (Y registerini doldur), STY (Y registerini boşalt) komutları mevcuttur. Aşağıdaki programda şu ana kadar tanıştığımız tüm komutlar kullanılmıştır.

A 1500 LDA # $01
A 1502 LDX # $00
A 1504 LDY #$02
A 1506 STA $0400
A 1509 STX $D800
A 1S0C STY $0401
A 150F STX $D801
A 1512 STA $0402
A 1515 STX $D802
A 1515 RTS

Beklendiği gibi bu program ekranın sağ üst köşesine “ABA” harflerini basacaktır. Burada X register STX komutu ile üç defa okunmuştur. Şu ana dek LDA komutunu sadece dolaysız adresleme yöntemi ile kullandık. Şimdi isterseniz akümülatörü STA komutundan tanıdığımız mutlak adresleme yöntemi ile yükleyelim.

A 1518 LDA $D800

Bu şekilde $D800 adresinde kayıtlı olan değer akümülatöre yüklenecektir. Bu değer $1509'da sıfır değeri almıştır. Yine devam edelim:

A 151B STA $0403
A STX $D803
A 1521 RTS

SYS 5376 ile programı çalıştırdığınızda ekranın sol üst köşesinde daha önce beliren üç harfin yanına bir “Ğ” işareti eklenecektir. LDA komutunu dolaysız adresleme yöntemi ile kullandığımızda (örneğin LDA #$01) hafızada 2 bayt işgal ettiğini daha önce belirtmiştik. Mutlak adresleme yöntemi kullanıldığında ise (örneğin LDA $D800) bu iş için 3 bayt harcanacaktır. Zaten hemen hemen tüm monitör programları bir Assembler satırı yazılıp RETURN'e basıldığında o satırın onaltılık sayı sistemindeki kodları hemen yanında gösterilir. Örneğin LDA #$01 ve LDA $D800 komutları şu şekilde gösterilecektir:

1500 A9 01 LDA $ $01
İSI8$ADOOD8 — LDA $D800
Her satırın başındaki ilk sayı LDA

komutuna aittir, fakat görüldüğü gibi

“ bunlar farklıdır. Buradan şu sonucu çıkarabiliriz: Onaltılık sistemdeki bir kod hem makine dilinde bir komutu, hem de kullanılan adresleme yöntemini belirtmektedir. Aynı şekilde LDX ve LDY için de dolaysız ve mutlak adresleme yöntemleri mevcuttur. STX ve STY için dolaysız adresleme kullanılmaz. Şu ana dek öğrendiğimiz komutların adresleme yöntemleri ve onaltılık sistemdeki kodları Resim 1'deki tabloda gösterilmiştir. Tablonun son sütununda her komutun statüs registerinde etkilediği göstergeler (flag) belirtilmiştir. Sondan bir önceki sütunda ise her komutun yorumlanabilmesi için harcanan süre yer almaktadır. Burada birim olarak çevrim (cycle) sayısı kullanılmıştır. Her bir çevrimin 1 mikrosaniye olduğu düşünülürse yukarıdaki programımız için 48 mikrosaniye sürecektir. Aynı programın Basic karşılığı ise aşağı yukarı 100 kat fazla zaman (0,05 saniye) harcayacaktır.

Assembler İşlemlerle işlemleri:

Şimdi Assembler programlarken çok sık kullanılan ikilik ve onaltılık sayı sistemlerini daha yakından inceleyeceğiz. Bilgisayarımızın algılayabildiği sadece iki rakam vardır: 0 ve 1. Eğer elektrik varsa 1, yoksa 0. Onaltılık sayı sistemini ise bilgisayar doğrudan doğruya kesinlikle tanımaz. Yalnız bu sistemin ikilik sistemle büyük benzerliği vardır. Örneğin en büyük tek basamaklı onaltılık sayı olan $F, ikilik sistemde 1111'e yani yarım bayt'a eş değerdedir. Bir bayt ise (1111-1111) $FF'e eş değerdir. Bildiğiniz gibi C-64'ün tüm belleği 65535 bayttır ve bu $FFFF'e karşılık gelmektedir. Dolayısıyla onaltılık sayı sistemini kullanarak istenen her adresi Low ve High Byte olmak üzere iki bayt halinde belirtmek mümkündür. Makina dilinde program yazarken oldukça sık kullanacağımız ikilik tabana göre hesap işlemleri aslında her zaman kullandığımız dört işleme oldukça benzemektedir:

o o 1 1

Burada son toplama işlemindeki iki tabanına göre 10 desimal olarak 2'ye karşılık gelmektedir. Örnek olarak 2+1=3 işlemini ikilik sistemde yapalım:

10 (desimal olarak 2) 01 (desimal olarak 1) = 11 (desimal olarak 3)

Görüldüğü gibi toplama işlemi aynı desimal sayılarda olduğu gibi sütunlar halinde yapılmaktadır. Elde kalan sayılar ise bir sonraki sütuna aktarılmaktadır. Örneğin:

10 (desimal olarak 2) + 10 (desimal olarak 2) = 100 (desimal olarak 4)

İkinci sütunda yer alan 1+1=10 olduğu için sonuç üç rakamlı çıkmıştır.

Altı

yeni komut daha:

INX, “Increment X-Register” yani X registerinin içeriğini 1 arttırmak demektir. Buna karşılık INY aynı işi Y registeri için yapar. INC ise herhangi bir baytın içerdiği değeri 1 arttırmaktadır. INX ve INY daha önceki RTS gibi 1 baytlık komuttur ve ardında herhangi bir parametre yer almaz. INC kullanıldığında ise bilgisayara hangi baytın değerinin arttırılacağı belirtilmelidir. Bu nedenle komutun kendisi ile birlikte 3 bayt harcanır. DEX, DEY ve DEC yukarıdaki arttırma işleminin tersini yani eksiltme işlemi yapmaktadırlar. Burada DEX “Decrement X Register” yani X registerini 1 eksilt anlamına gelmektedir. Diğer komutların anlamları ve harcadıkları bayt sayıları da benzer şekildedir. Şimdi öğrendiklerimizi bir programda uygulayalım:

1500 LDA # $00
1502 LDX # $01
1502 STA $d800
1507 STX $0400
1508 BRK

Yukarıdaki satırları yazdıktan sonra G 1500 yazıp RETURN'e basın.

Ekranın sol üst köşesinde tekrar “ABA” harfleri siyah renkte gözükecektir. Şimdi bu programda neler olup bittiğini inceleyelim. Önce akümülatörün içerdiği değeri (siyahın değeri olan 0) ekran renk belleğine ($D800) ve X registerinin içerdiği değer olan 1 (A harfinin POKE kodu) ilk ekran belleğine ($0400) yazılır. Daha sonra X registerinin içeriği 1 (B harfinin POKE değeri) arttırılır ve ikinci ekran belleğine ($0401) yazılır. Daha sonra DEX ile X registeri azaltılır ve üçüncü ekran belleğine ($0401) yazılır. Herhalde farketmişsinizdir; bu sistemi kullanarak birçok kez tekrarlanan bir döngüyü kontrol edebilirsiniz. Örneğin herhangi bir işlem 20 defa tekrarlanacaksa her seferinde X registerini INX ile 1 arttırır ve (daha sonra değineceğiz) X registerinin 20 olup olmadığını anlayabiliriz. Burada hemen FOR-NEXT döngüleri aklımıza gelmekte. Aynı Basic'te olduğu gibi makina dilinde de döngüleri tersten saydırabiliriz. Bunun için DEX veya DEY komutunu kullanmamız yeterli olacaktır. Bu aylık da bu kadar. Gelecek ay BRANCH komutlarını incelemek üzere şimdilik hoşçakalın!