Bu sayfadaki yazılar
Sayfanın metni
Sayfa 49
DERLEYİCİLER
da az yer kaplayacak. Amacımız; sonuçta en iyi ve kaliteli makina kodunu oluşturmak.
ÖRNEK PROGRAM 2b:
1 START: LEA bufferl.A0 2 LEA buffer2.A 1 3 MOVE.B (A0)+.(A1)+ 4 CMP.L #buffer2,A0 5 BNE Ll 6 RTS 7 buffer1: dc.b 1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1 8 buffer2: dc.b 0,0,0,0,0,0,0,0,0,0,0, 0,0,0.0,0.0,0,0,0 işte sonuç; program sekiz satırdan altı satıra indi. Ve en önemlisi 5 satırdan olu- şan ve zaman alan döngü, yeni örnekte üç satıra indi ve programa ortalama %50 iş- leyiş hızı kazandırıldı. Şimdi ilk örneği- miz ile yenisi arasındaki değişikliklerden söz edelim.
Yeni programda 1. ve 2. satırlar ilki ile aynı işlemi yapıyor. Fakat yukarıda da anlattığımız gibi LEA komutu ile bu işi daha hızlı yapıyoruz. Ve bu iki satırda gereksiz yere koca iki MOVE komutunu kullanmak yerine bu iş için hazırlanmış LEA komutlarını görevlendiriyoruz.
İşte yeni programda farklı bir komut kullanımı:
MOVE.B (A0)+,(A1)+ Şimdi örneğimize şöyle bir bakın. İlk programa göre hangi satırları kaldırmışız?
İkinci örnekte olmayan komutlar. ADD komutları. Burada döngü içerisindeki ADD komutlarının yaptığı işi MOVE komutunun üzerine, adres registeri ibarelerin sonuna + işaretini koyarak yapmaktayız.
MOVE komutu burada işleme girmeden önce A0 ve A1 adres registerlerindeki değer, komutun icrasından sonra birer basamak artırılmış oluyor. Yani ilk örnekte olduğu gibi "Taşı sonra Artır" ifadesi yerine "Taşı-Artır" ifadesini kullanmış oluyoruz. Tabii böyle kullanım ile bu döngü içerisindeki ADD komutların gereksizliği hemen ortaya çıkıyor.
Peki örneğimizi gayet güzel kısalttık da, daha başka şeyler yapılamaz mı acaba? Tabii ki yapılabilir. L1 ve BNE arasındaki 20 defa gerçekleşen döngüyü yüce MOVE komutu ile 4 defada gerçekleştirebiliriz. Nasıl mı? İşte şöyle...
Programda taşıma işlemini yapan MOVE komutu tek tek byte'ları alıp yeni yerine koyuyordu. Ama ne gerek var bu işi tek tek yapmaya? Bildiğiniz gibi MOVE komutunun BYTE modundan başka WORD ve LONGWORD modları bulunmaktadır. Yani örneğimizdeki MOVE komutunu WORD modunda kullanarak 10 defada ve LONGWORD modunda kullanarak ise 4 defada taşıma işlemini gerçekleştirebiliriz. Yani satır değişikliklerini yapınca programımız şu şekilde olacaktır.
ÖRNEK PROGRAM 2c :
1 START: LEA bufferl.A0 2 LEA buffer2.Al 3 L1: MOVE.L (A0)+,(A1)+ 4 CMP.L #buffer2,A0 5 BNE Ll 6 RTS 7 buffer1: dc.b 1,1,1,1,1,1,1,1,1,1,1 1,1,1,1,1,1,1,1,1 8 buffer2: dc.b 0.0.0.0.0.0,0,0,0,0,0. 0.0. 0,0,0,0, 0.0.0 Evet. Programın kapladığı hafıza alanın- da bir değişiklik olmadı. Fakat hızında 4 kat değişiklik oldu. Program 20 byte'ı ko- mutun BYTE modunda 20 defada taşıya- cakken, LONGWORD modunda 4 defada taşıyacaktır.
Yalnız bu kullanımlar sırasında birkaç noktaya dikkat edilmesi gerekir. Örneğin ben taşınacak değerlerin 20 byte uzunluğunda olduğunu bildiğimden A0'ın dörder defa katlanarak buffer2 değerine ulaşacağını tamsayı olarak hesapladım. Fakat taşınacak bilgi 10, 20, 30 gibi dördün katları olmayabilirdi. O zaman bu örnekteki döngü hiçbir zaman buffer2 değerine eşit olamaz ve BNE komutu da buffer2 değerini hiçbir şekilde yakalayamazdı. Tabii bu gibi durumlarda, BNE komutu yerine Branch Greater Than (BGT) kullanarak sayının buffer2 değerine eşit olup olmadığını değil, buffer2 değerini geçip geçmediğini kontrol ettiririz.
Evet, şu ana kadar programı maksimum kısalık ve elimizden geldiği kadar hıza kazandırdık ve döngü sayısını en aza indirgemiş olduk. Şimdi örneğimizin yapısında topluca bir değişikliğe yani devrime ne dersiniz.
ÖRNEK PROGRAM 2d :
1 START: LEA bufferl.A0 2 LEA buffer2.A1 3 MOVE.L #20.D0 4 L1: MOVE.B (A0)+,(A1)+ 5 DBF D0.L1 6 RTS 7 buffer1 1,1,1,1,1,1,1,1,1,1,1 1,1,1,1,1.1,1,1.1.1 8 buffer2: dc.b 0,0,0,0,0,0,0,0.0,0,0, 0,0,0,0,0,0.0.0.0
BASIC'teki FOR NEXT döngüsünü hepinizin bildiğine eminim. İşte size Assembler'da yeni bir komut ve FOR NEXT döngüsü:
DBF komutu aslında DBcc komut dizisinin bir parçasıdır. Yaptığı işi BNE komutuna benzetebilirsiniz. DBcc komutunu kısaca anlatmak gerekirse, parametresinde belirtilen registerleri kontrol eder, değerlerini değiştirir ve sonucuna göre dallanma yapar.
Örnekte ise DBcc komutunun bir kolu olan False'i DBF modunda kullanıyoruz. Daha önce döngünün sayısını D0 data registerine yazıyoruz. İşlemci, bir DBF komutu üzerinden geçerken her defasında D0'ı bir azaltır ve 0'a ulaşıncaya kadar döngüyü devam ettirir.
DBcc komut dizisindeki komutlar parametre olarak Bcc'dekilere benzerler. Fakat işlemleri birbirlerinin zıt şeklidir. Örneğin BEQ komutu işlemin sonucu eşit ise dallanma yaparken, DBEQ işlemin sonucu eşit değilse dallanma yapar. Veya BNE komutu işlemin sonucu eşit değilse dallanma yaparken, DBNE komutu ise işlemin sonucu eşit ise dallanma yapar. Tabii DBcc komutları, CMP komutunun yaptığı gibi aynı anda registerleri kontrol edebilir ve sonucunu değerlendirip dallanmayı gerçekleştirirler.
Programımızda yapısal değişiklikleri de yaptıktan sonra, yine hız ile alakalı bir değişiklikten söz etmek istiyorum. Nasıl yukarıda döngüleri azaltmak için MOVE komutunun LONGWORD modunu kullanıyorsak aynı şekilde bu döngüde de LONGWORD modunu kullanıp işlemleri 4 kat hızlandırabiliriz.
ÖRNEK PROGRAM 2e:
1 START: LEA bufferl,A0 2 LEA buffer2,Al 3 MOVE.L #4,D0 4L1: MOVE.L (A0)+,(A1)+ 5 DBF D0,L1 6 RTS 7 bufferl: dc.b 1,1,1,1,1,1,1,1,1, 1.1. 1,1,1.1,1.1,1.1,1 8 buffer2: dc.b 0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0
Döngünün sayısını belirten D0 data registerini 4 kodlayıp, taşımayı yapan MOVE komutunu LONGWORD kullanınca, 20'şer dörder dörder bütün değerleri 4 turda kopyalayabiliriz.
Gelecek sayıda yeni bir programın anlatımına geçeceğiz. Makine dili bilginizin temelini oluşturacak bu örnek programların işleyişlerini çok iyi kavramalısınız. Gelecekte yüzlerce satırdan oluşan programları yazarken sürat ve akıcılık, bir o kadar da hatasız yazım ve kodlama, temel komutların beyninize çok iyi yerleşmesinden sonra oluşacaktır. İleride gerçek anlamda makine kodu programlaması yaparken karşılaşacağınız bir problemi makine dilinde yazmak için değil, çözmek için uğraşmalısınız.
Klavyeyle gezinmek için ← ve → tuşları.
Sayfa 48
Merhaba. Bu sayımızda yeni bir makine dili programı ile yazımıza devam ediyoruz.
İkinci örnek programımızda amacımız, belli bir hafıza bölgesini başka bir yere taşıma ya da kopyalama işlemi. Makina dili programlarında sık sık kullanacağımız için, bu taşıma işlemlerini çok iyi öğrenmeniz gerekiyor.
ÖRNEK PROGRAM 2a:
1 START: MOVE.L #bufferl,A0 2 MOVE.L #buffer2,Al 3L1: MOVE.B (A0),(A1) 4 ADD.L #1,A0 5 ADD.L #1,A1 6 CMP.L #buffer2,A0 7 BNE Ll 8 RTS 9 bufferl: dc.b 1,1,1,1,1,1,1,1,1,1,1,1,1 1,1,1,1,1,1,1 10 buffer2: dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0 0,0,0,0,0,0,0
Programın yaptığı iş; buffer1 diye adlandırılan ve 20 byte uzunluğundaki hafıza bölgesini, buffer2 diye adlandırılan hafıza bölgesine taşımak. 68000 işlemci ile bu tür işlemleri yapmak çok rahat. Çünkü 32 bit uzunluğundaki adres ve data registerleri ile adreslerden sayıları almak, taşınacakları adreslere koymak çok kolay. Hele 68000'in göz bebeği olan MOVE komutunun bir defada 32 bitlik bilgiyi alıp başka bir yere koyduğunu ve bu işlemi tek hareket ile yaptığını düşünürsek taşıma işleminin rahatlığını siz de anlayacaksınız.
Şimdi programımızın açıklamasına geçelim.
Örnek programımızın kodu, Start label'ı ile buffer1 label'ı arasındaki hafıza bölgesinde bulunuyor.
Buffer1'den Buffer2'ye kadar olan 20 byte'lık hafıza bölgesindeki her byte'da 1 değeri bulunuyor. Ve buffer2'den itibaren 20 byte'da 0 değeri bulunuyor.
SATIRI:
START: MOVE.L #buffer1,A0 Programımızın ilk satırında buffer1 değerini A0 adres registerine gönderiyoruz. Bu satırın anlamı, daha önce de anlattığımız gibi programda sık sık kullanılan hafıza adreslerini bir adres registerine gönderip rahat bir kullanım ortamı oluşturmak.
SATIR-2:
MOVE.L #buffer2,A1 İkinci satırda da birinci satırdaki gibi bir atama işlemi yapılıyor. Buffer2 değerini A1 adres registerine gönderiyoruz.
Programın birinci ve ikinci satırlarında amacımız, taşıma işlemini yapacağımız hafıza bölgelerinin başlangıçlarını temsil eden bu label'ları (buffer1 ve buffer2) A0 ve A1 registerlerinin adı ve içeriği ile kullanmak olacaktır. Ve program içindeki L1: Label'ı ile BNE komutu arasındaki döngüde, ADD komutları ile A0 ve A1 adres registerleri içeriğindeki değerleri artırıp, taşıma işinin yapılacağı yeni byte'ı tespit ediyoruz.
Aslında 68000 makina dilinde, ilk iki satırdaki komutlar yerine, gerçekten adres registerlerine atama işlemi yapan komutlar da bulunmaktadır. Örneğin LEA (Load Effective Address) komutu gibi. Bu komutu örneğimizdeki yerine koyarsak, ilk iki satır şu şekilde de olabilir.
Bufferl,A0 buffer2,Al
Bu iki satır örnekteki işlemi MOVE komutundan çok daha kısa sürede ve program kodu üzerinden düşünürsek, en az miktarda hafıza harcayarak yapabilirler. Size tavsiyem, adres registerlerine atama yaparken hız ve işleyiş kolaylığı bakımından bunları kullanmaktır. LEA komutunun bu programdaki değişikliklerini ve etkilerini bundan sonraki örneğimizde görebilirsiniz.
SATIR-3:
L1: MOVE.B (A0),(A1) Burada taşıma işleminin adımları gerçekleştiriliyor. A0 adres registerinin içeriğindeki adresin gösterdiği hafıza bölgesindeki değer, A1 registerinin gösterdiği hafıza bölgesine gönderiliyor. Burada MOVE komutu tek byte'lık taşıma işlemi yapıyor.
SATIR-4:
ADD.L #1,A0 Bu satırda, ADD komutu ile A0 registerindeki sayı bir değer artırılmış oluyor.
SATIR-5:
ADD.L #1,A1 Bu satırda bir üst satır gibi, ama bu sefer A1 registerindeki değer bir artırılmış oluyor.
Son iki satırdaki amacımız ise, L1 label'ı ile BNE komutu arasındaki döngü esnasında bu satırlarda devamlı olarak A0 ve A1 adres registerlerindeki sayıları bir değer artırmak ve MOVE.B (A0),(A1) satırındaki adres registerlerine yeni alınacak ve konacağı değerlerin hafıza adreslerini bildirmek.
SATIR-6:
CMP.L #buffer2,A0 Programdaki döngünün son satırı burası olmaktadır. Buffer2 değeri A0 registeri ile karşılaştırılıyor. Sonuç bir alt satırdaki BNE komutu tarafından okunacaktır.
SATIR-7:
BNE L1 Bir üst satırdaki işlemin sonucunda buffer2 değeri adres registeri A0'da bulunan değeri aşmamışsa L1 label'ına, aşmışsa programın devamına gidecektir.
SATIR-8:
RTS İşte, döngülerin sonu olan satır. RTS komutu ile programdan çıkıyoruz.
İşlemci, programda satırları okurken şu mantıkla ilerleme kaydetmiştir.
I - İlk iki satırda A0 ve A1 registerlerine buffer1 ve buffer2 değerlerinin atamasını yapmıştır. LEA LEA
II - Alınacak byte'ın bulunduğu hafıza bölgesini gösteren değer yeri olan A0 ve konacak byte'ın hafıza değerini gösteren A1 registerlerini, MOVE komutunu kullanarak ilk byte'ın taşımasını yapmış oluruz.
III - ADD komutları ile her iki adres registerindeki adreslerin değerlerini birer basamak artırarak yeni taşınacak byte'ın bulunduğu hafıza adresini oluşturur.
IV - Bu değerlerin buffer2 yani buffer1'in sonunu bildirip bildirmediğini kontrol ederiz.
V - Bne'ye geldiğimizde, Cmp komutunun sonucuna göre hareket ediliyor. Değer belirtilen sınırı geçmişse programa devam ediliyor, eğer geçmemişse L1 label'ına atlanıp devam ediliyor.
VI - Ve L1-BNE döngüsünü 20 defa tekrarladıktan sonra sonuçta RTS'ye gelinip programdan çıkılıyor.
Sonuçta buffer1'de bulunan 20 adet 01 değerini almış olan byte buffer2'ye taşınmış oluyor.
Şimdi bu programı, yukarıda satırları açıklarken bir kısmına değindiğim değişikliklerle yeniden yazalım. Böylece programımız daha hızlı çalışacağı gibi, hafıza-