Amiga Dünyası sayı 7, sayfa 44

Bu sayfadaki yazılar

Sayfanın metni

Sayfa 44

ÖRNEK PROGRAM 3b:

1 START: LEA buffer,A0

2 MOVE.L#20,D0 3 L1: CMP.B #5,(A0) 4 BEQ L2 5 SUB.L #1,D0 6 CMPL #0,D0 7 BNE L1 8 L2: RTS 9 Buffer dc.b 0,0,0,0,0,0,0,0,0, 0,0,0,0,0,5,0,0,0,0,0

Evet. Rutinin bu hali ile ilk haline şöyle bir göz gezdirin, ilk haline göre bu hali biraz kısıtlamalı oldu. Neden mi? Şöyle;

Eskisinde arama işlemi yaptığımız ve ayırdığımız hafıza bölgesinin başını ve sonunu label'lar ile belirlemiştik. Şimdi ise bölgenin başına bir label (buffer) ve sonuna ise hiçbir şey koymadık. Peki durum böyle olunca ve diyelim ki hafıza bölgesinin 15'inci byte'ında 5 değeri bulunmuyor. Bu şekilde ayrılan bölgenin sonunu nasıl bulacağız? Bu sorunun cevabı 2. satırda.

Yukarıda rutinin bu halinin kısıtlamalı olduğundan bahsetmiştim. Bunun nedeni ise, ikinci satırdaki move.l #20,d0 olmaktadır. Biz bu satırla birinci programdaki bufferend label'ı yerine bölgenin sonunu değil de, uzunluğunu D0 data registerine göndermiş oluyoruz. Ve bunu yine programın her döngüsü esnasında kontrol ederek arama bölgesinin sonunu buluyoruz.

Kısıtlama işine gelince: Şimdi birinci rutin için bazı şeyler söylemek istiyorum. Buffer ile bufferend label'ları arasında kaç byte olduğu bizi ilgilendirmemektedir. Biz nasıl olsa ayırdığımız hafıza bölgesinin başlangıcını ve sonunu label'lar aracılığı ile biliyoruz. Arada uzunluğun kaç byte olduğunu bilmemiz ve bunu bir yerlere yazmamız gerekmez. Bölgenin başlangıcını bulmak istediğimizde buffer label'ının adresini okumamız, sonunu bulmak istediğimizde ise bufferend label'ını okumamız ve data satırlarının uzunluğunu öğrenmemiz gerektiği zaman ise bufferend label'ının değerinden buffer label'ının değerini çıkarmamız (bufferend-buffer) yeterlidir, ikinci rutinde ise programa bazı kısıtlamalar getirdik. Yani başlarken uzunluğun 20 değer olduğunu (move.l #20,d0) ile kaydettik diğer bir deyişle formatladık.

Şu anda birinci rutinin çok daha kullanışlı olduğunu ve ikincisine kısıtlamalı olduğu için hiçbir zaman gerek duyulmayacağı fikrine kapılabilirsiniz. Veya ikisinin de çok az farkları olduğu ve sonuçları nasıl olsa aynı olduğu için kullanımlarında fark olmadığını düşünebilirsiniz. Ama ikisinin de kullanım alanları farklı şekilde olabiliyor. Program yazarken ana programdaki görevlerine göre kullanım farklılıkları ve kolaylıkları gösterebiliyorlar. Biz de bizim için hangisi gerekli ise onu kullanıyoruz. Zaten bu tür döngü işlemlerinde döngüye şekil verirken ne tür şekilde kullanacağımız kendiliğinden ortaya çıkıyor.

Bu arada unutmadan ikinci örnek hakkında bir şey söylemek istiyorum. Rutinin sonucunda işlemci bölgenin 15'inci byte'ında 5 değerini yakalayınca şöyle davranacaktır. Üçüncü satırdaki cmp komutunun etkisi ile A0'daki buffer değeri her defasında bir değer artacaktır. Ve RTS komutuna yani programın sonucuna olan dallanma dördüncü satırda gerçekleştiği için program sona erdiğinde 5 değerinin hafıza bölgesinde yerini gösteren A0 registerinde +1 değeri bulunmaktadır.

Yine iki örnek için bir açıklama daha getirelim, iki rutine de başlarken buffer label'ını ve gösterdiği hafıza bölgesinin değerini A0 registerine atadık. Bu A0 registerinin rutin içerisindeki birinci görevi olmaktadır. Daha sonra programın akışı ile döngü içerisinde bu registeri bir sayaç olarak kullandık. Bize her döngü dilimi içerisinde arama bölgesinde bir sonraki byte'ın hafıza adresinin değerini verdi. Bu da onun ikinci görevi oldu.

Şimdi yeni bir rutin ve örnek dizisine geçiyoruz. Bu sefer amacımız bir önceki örnek gibi, fakat daha kapsamlı olarak bir byte'ın aratılması yerine birkaç byte'ın birden, bir hafıza bölgesinde aranılmasını içeriyor.

Bir hafıza bölgesinde birden çok byte'ı aynı anda aramanın binbir türlü yolu vardır. Ve herkes coding stiline göre kendine göre yöntemler gerçekleştirebilir. Ben size bir kısa bir de uzun yoldan bu işi nasıl yapacağınızı ifade etmeye çalışacağım.

Örneğimizde amacımız PERİ kelimesini arama bölgesi içerisinden bulup, başlangıç adresini belirlemek olacaktır.

ÖRNEK PROGRAM 4a:

1 START: LEA Buffer,A0 2 LEA bufferend A1 3 Ll: CMP.B #"P",(A0) 4 BNE L2 5 CMP.B #"E",1(A0) 6 BNE L2 7 CMP.B #"R",2(A0) 8 BNE L2 9 CMP.B #'T'3(A0) 10 BNE L2 11 JMP L3 12 L2: ADD.L #1A0 13 CMRL A1,A0 14 BNE L1 15 L3: RTS 16 buffer dc.b'ABCHGKPOIDF PEGFGDPERIDFDSFRETRYREY"

17 bufferend:

SATIR-1:

START: LEA buffer,A0 Rutinimizin başlangıç satırında bir adres atama komutu (LEA = Load Effective Address) bulunmaktadır. Görevi ise Buffer label'ının gösterdiği hafıza adresini A0 adres registerine atamak olmaktadır. Programdaki görevi ise aranacak kelimenin bulunduğu hafıza adresinin başlangıcını adres registeri üzerinden kullanmak. Yani amacımız buffer isimli sabit hafıza adresini, bir adres registeri içeriğine atayıp rahat bir şekilde, ona değişken bir şekil vermek oluyor.

SATIR-2:

LEA bufferend,A1 ikinci komutumuz ise yine birincisi gibi bir atama işlemi yapar, bufferend isimli hafıza adresini temsil eden label olarak A1 adres registerine atanmaktadır.

SATIR-3:

L1: CMP.B #"P",(A0) Üçüncü satıra gelince, okumayı durdurup bu satıra şöyle yan gözle bir bakın. Karşınızda mükemmel bir mimari düşünüş eseri durmaktadır! Nasıl mı? İşte şöyle...

Assembler'ın en büyük ve benim en hoşuma giden kolaylıklarından biri karşınızda.

CMP.B #"P",(A0) Bu satırda bulunan komuttaki #"P" ifadesinin ne olduğunu anlayabildiniz mi?

Bu ifadenin anlamı #"P" = #80 = #$50 olmaktadır. Yani komuttaki yerine koyarsak.

a) Cmp.b #"P",(a0) b) Cmp.b #80,(a0) c) Cmp.b #$50,(a0)

Gördüğünüz gibi bu satırların anlamı P harfinin ASCII kod değerini veya 80 değerini veya $50 değerini A0 adres registerinin gösterdiği adresteki değer ile karşılaştırmak oluyor, işte bu kullanım assembler program listesinde harf kullanılması gereken yerlerde onların ASCII kodlarını kullanmak yerine, gerçek kendi harfleri ile ifadesini sağlıyor. Assembler derleyicisi listedeki bu tür kullanımların bulunduğu satırları obje kodunu üretirken yapısı gereği ASCII kodlarını tespit edip kod içerisinde bulunması gerektiği yerlere koymaktadır.

Tabii bu kullanım assemblerda konabilecek bütün komutlar için geçerlidir. Bir kaç örnek verilmek gerekirse;

a) Move.b #"P",(a0) b) Move.l #"SCSI",(a0) c) Jmp "SCSI" d) Add.l #"A",d0 e) Add.l #"A","SCSI"

gibi kullanabiliriz. Çift tırnak içerisinde verdiğimiz ifadeler komutların değer kullanım formatları gereği üç türlü olmalıdır. Yani BYTE veya WORD veya LONG WORD olmalıdır.

Yukarıda a kullanımında P harfinin değeri olan 80, tek harf olarak kullanıldığından move komutu byte modunda kullanılmıştır, b kullanımında ise SCSI'yı oluşturan LONGWORD değer, yani; $53,$43,$53,$49 sayıları ifade edilmektedir, c kullanımında ise SCSI yalın bir değer olmaktan çıkarak direkt bir adres ifadesi olmaktadır. Ve bu adres değeri de $53435349 adresi olmaktadır, d kullanımında ise A değeri yani ASCII 65 değeri olarak işlem görmektedir. Son olarak e kullanımında 65 değeri SCSI yani $53435349 adresindeki sayı ile toplanması şeklinde işlem görecektir.

Bu sayıdaki yazı dizimizi noktalıyoruz. Konumuza ve son örneğimizin diğer satırlarının açıklamasına diğer sayıda devam edeceğiz. Hoşçakalın.

Klavyeyle gezinmek için ← ve → tuşları.