Makine Diline Merhaba (3)
5. Mantıksal İşlem Komutları
Mantıksal işlemler de, aritmetik işlemler gibi iki değer arasında yürütülür. Aritmetik işlemlerle diğer bir benzerlik, operand'lardan birinin akümülatör'de bulunma zorunluluğu. Diğer operand için tanıdık adresleme tiplerimiz mevcut. Mantıksal işlem yapıldıktan sonra sonuç burada da akümülatör'e alınmakta. 6510 ana işlem ünitemiz üç türlü mantıksal işlem yapabiliyor.
VE (AND) işlemi:
Bu işlem akümülatör ve diğer operand arasında bit bazında yürütülür. Bazılarınızın daha evvelden biliyor olabileceği “VE” işlemi, aslında iki adet birer bitlik veriler arasında yürütülür. Bu işlemin sonucu yalnızca her iki veri de 1 olduğunda “1”dir. Bunun ne anlama geldiğini ufak bir mantıksal tablo yaparak inceleyelim:
0 AND 0 OANDI - 1 AND O DANDİ
|
Bit bazında “VE” işlemini gördükten sonra, şimdi de byte bazında bu olay nasıl gerçekleşiyor, gelin hep beraber bir örnek üzerinde görelim:
AND
Diyelim ki akümülatör bu işlemden önce $5D içermekte, işlem şöyle gerçekleşir:
$5D 01011101, $37 00110111, $15 00010101
Sonuç olarak 00010101 yani $15 elde ettik. Bu işlemi BASIC'te yaptırmak için tabii ki AND komutunu kullanacağız.
Ayhan KALAYLIOĞLU
AANDS5S5 ($37)
Burada A'nın değeri; AND $37, yani A=93 AND 55'tir. Sonuç olarak 21, yani $15 elde ederiz. AND işlemi sırasında N- ve Z-flag'ları etkilenir. Sonuç olarak sıfır elde edersek, Z-flag'ı yanar. Sonucun 7'nci biti yanıksa N-flag yanar. Aşağıda AND işlemine ait komut kodlarını ve adresleme tiplerini bulacaksınız.
Adresleme tipi AND direkt $29, absolut $2D, 0. sayfa $25, X-indeksli $3D, Y-indeksli $39, 0. sayfa X-indeks $35, indirekt indeksli $31, indeksli indirekt $21
VEYA (OR) işlemi
Bu işlem de akümülatör ve veri arasında bit bazında yürütülür. Şayet iki bitten bir tanesi bile “1”se sonuç “1” olur. Küçük bir tabloda inceleyelim:
0 ORA 0 - O 0 ORA | - | 1OnrRA 0 - | 1OnrRA | - |
Bu veya işlemine 1, 1 kombinasyonunu da içerdiği (sonucu olumlu olduğu) için aynı zamanda “veya” (inclusive OR) denir. “İçermeyen veya” (exclusive OR) işlemini birazdan göreceğiz. VEYA işlemi sırasında da N- ve Z-flag'ları etkilenir. Şimdi işlemimiz byte bazında nasıl yürüyor, onu görelim:
ORA
Diyelim ki akümülatör $5D içeriyor. İşlem şöyle gelişir:
$5D 01011101 $37 00110111
$7F
Sonuç olarak yani $7F elde ettik. Aynı işlemi BASIC'te yaptırmak isteseydik OR komutunu kullanmamız gerekecekti:
A - A OR 55
Burada A'nın değeri A=$5D OR $37, yani A=93 OR 55 işlemiyle belirlenir. Sonuç ise 127, yani $7F'dir. Aşağıdaki tabloda ORA işleminin komut kodlarını ve adresleme tiplerini bulacaksınız.
Adresleme tipi ORA direkt $09 absolut $0D 0. sayfa $05 X-indeksli $1D Y-indeksli $19 0.sayfa X-indeks $15 indirekt indeksli $11 indeksli indirekt $01
İÇERMEYEN VEYA (exclusive or, EXOR) işlemi
EXOR işlemi sırasında da, bit bazında yürür tüm işlem. Sonuç, verilerden sadece biri “1” değeri taşıyorsa “1”dir. Değer tablomuzda bu olayı daha yakından görelim:
0 EOR O 0 EOR | 1 EOR 0 1 EOR |
0 0 ll
Görüldüğü gibi bu ilginç işlemde sonuç sadece iki değer birbirinden farklı ise olumludur (= 1). Bu işlem sırasında da N- ve Z-flag'ları etkilenir. BASIC'te bu işlemi yapan bir komutumuz olmadığı için ufak bir döngüde, bu işlem bit bit gerçekleştirilmeli. Böyle bir örnek burada sadece kalabalık yaratmaktan başka bir şey yapmayacağı için böyle bir örneği meraklı programcı arkadaşlarımızın özel
zevkine bırakıyoruz. Şimdi byte bazında olayı, bir örnekle görelim:
EOR 44$37
Burada da akümülatör $5D içersin. Bakalım neler oluyor:
$5D 01011101 $37 00110111
$6A 01101010
Sonuç olarak yani $6A (106) elde ederiz. Bu komutun en çok kullanıldığı biçimini belirtelim. Bu komut genelde akümülatör'ün belli bazı bitlerinin içeriğini tersine (0->1 veya 1->0) çevirmekte kullanılıyor. Örnek olarak AND $FF işlemi akümülatör'ün içeriği ne olursa olsun, tüm bitlerini tersine çevirir. Aşağıdaki tabloda EOR işleminin adresleme tiplerini ve komut kodlarını bulacaksınız.
000
Adresleme tipi EOR direkt $49 absolut $4D 0. sayfa $45 X-indeksli $5D Y-indeksli $59 0.sayfa X-indeks $55 indirekt indeksli $51 indeksli indirekt $41
BIT komutu
BIT komutu 65XX ailesinden olan ana işlem ünitelerinin değişik bir özelliğidir. Bu işlem hiçbir register'in içeriğini değiştirmez. Sadece flag'larını yürütülen işleme göre değiştirir. Etkilenen flag'lar Z-, N- ve V-flag'larıdır. Z-flag'ı akümülatör'le, veri arasında yürütülen hayali bir “ve” (AND) işlemine göre şekillenir. N-flag'ı verinin 7'nci bitinin kopyasıdır. V-flag'ı da 6'ncı bitle aynı içeriktedir. Bir kere daha hatırlatalım: Bu işlem sırasında ne register'lerin içeriği ne de hafızadaki verinin içeriği değişmez. Sadece bit'lere göre test yapılır ve sonuç flag'lara kaydedilir. Başka hiçbir şey değişmez. Örneğimiz bu olayı daha iyi açıklayacaktır:
BIT $1234
Diyelim ki akümülatörümüz $10
0x içeriyor. $1234 adresinin içeriği de $43 olsun. Yürütülen hayali “ve” işlemi şu sonucu verir:
$10 00010000 $43 01000011
$00 00000000
AND işlemi, sonuçta sıfır verdiğine göre Z-flag'ı yanacaktır. V-flag'ı verinin 6'ncı bitine eşit olacak demiştik, yani “1”. Verinin 7'nci biti “0” olduğu için N-flag'ı sönük olacaktır. Sonuçta şunu elde ederiz:
BIT komutu sadece iki adresleme tipine sahiptir:
Adresleme tipi BIT 0. sayfa $24 absolut $2C
6. Karşılaştırma Komutları
Bu gruba giren komutların yaptığı işlem; register'lere zarar vermeden içeriklerini hafızadaki verilerle karşılaştırmamızı sağlar. Sonuç BIT komutundaki gibi flag'ları etkiler. Flag'ların durumuna göre programın akışını değiştiren komutlar (bu komutları bir sonraki bölümde göreceğiz) yardımıyla, bir bakıma IF...THEN...ELSE yapısına sahip program akışı oluşturabiliriz. Karşılaştırma komutlarında verinin içeriği söz konusu register'in içeriğinden çıkartılır (aritmetik olarak). Bu işlem sırasında register'lerin içeriği değişmez. Fakat sonuca C-, N- ve Z-flag'ları belirlenir. Ana işlem ünitemizin üç çalışma register'i için de karşılaştırma komutları mevcuttur.
CMP komutu
Bu komut (CMP: to CoMPare) akümülatörün içeriğini hafızadaki veri ile karşılaştırmaya yarar. Operand (veri), akümülatörden çıkarılır (CARRY'ye dikkat etmeksizin). Şayet sonuçta “alma” olayı gerçekleşirse CARRY biti söner, tersi durumda da yanar. Şayet sonuç sıfır ise, yani veri akümülatöre eşitse, Z-flag'ı yanar, diğer durumlarda söner. Şayet sonuç $7F'ten büyükse (7'nci biti yanıksa), N-flag'ı yanar, yoksa söner. Gene bir örnek verelim:
CMP
İlk örneğimizde akümülatör $50 içersin. Yani $50-$30 işlemi yürütülecektir. Sonuç pozitif olduğu için (yani “alma” olmadığı için), CARRY biti yanacaktır. Sayılar birbirine eşit olmadığı için Z- (zero) flag'ı sönecektir. Sonuç olarak $20 elde ederiz, bu sayı $7F'ten büyük olmadığı için N-flag'ı sönük kalacaktır. Sonuç olarak; şu görünümü elde ederiz.
Diyelim ki akümülatörün içeriği $30. Burada CARRY biti gene yanacaktır, çünkü “alma” olayı yoktur. Fakat sonuç sıfır olduğu için, ZERO biti yanacaktır. N-flag'ı gene yanmayacaktır, çünkü sonuç $7F'ten büyük değildir. Sonuç olarak flag'lar bu durumu alacaktır:
Üçüncü örneğimizde, akümülatörün içeriği $10 olsun. Yapılan işlem $10-$30 = $E0 biçiminde gerçekleşecek ve görüldüğü gibi “alma” olayı olacaktır. C-flag'ı bu yüzden sönecektir. Tabii Z-flag'ı da. Sonucun 7'nci biti yanık olduğundan ($E0 = %11100000), N-flag'ı yanacaktır. Sonuç şudur:
Pratikte sonuçlar şöyle değerlendirilir:
C = 1; anlamı: büyük veya eşit. Z = 1; anlamı: eşit. C = 0; anlamı: küçüktür.
Şayet “büyüktür” şartını kontrol etmek istiyorsak, iki flag'a birden bağımlıyız. Bu durum:
Z — 1; anlamı büyüktür.
Bir kere daha hatırlatalım: Karşılaştırma komutları register'lerin veya operand'ların içeriğini değiştirmez. Sadece flag'lar değişir. Flag'ları değerlendiren komut grubunu bir sonraki bölümde inceleyeceğiz. Aşağıdaki tabloda CMP komutunun adresleme tiplerini ve kodlarını bulacaksınız.
Adresleme tipi CMP direkt $C9 absolut $CD
0. sayfa $C5 X-indeksli $DD Y-indeksli $D9 0. sayfa N-indeks $D5 indirekt indeksli $D1 indeksli indirekt $C1 CPX komutu
CPX komutu CMP komutundan farksız çalışır. Burada karşılaştırılan register, akümülatör değil X-register'dir. Burada da X-register'inin içeriği değişmez. Yukarıda tüm söylenenler, aynen CPX komutu için de geçerlidir. Yalnız CPX komutunun o kadar çok adresleme tipi yoktur. Aşağıdaki tabloda bu adresleme tiplerini ve karşılık gelen komut kodlarını bulacaksınız.
Adresleme tipi CPX direkt $E0 absolut $EC 0. sayfa $E4 CPY komutu
Burada, gene yukarıda söylenenler geçerliliğini koruyor. Fakat, bu sefer karşılaştırılan Y-register'i. Bu komut için de sadece üç adresleme tipi geçerli.
Adresleme tipi CPY direkt $C0 absolut $CC 0.cı sayfa $C4
7. Şartlı Programlama Komutları
Şimdi öğreneceğimiz komutlar
programlarımızın şarta bağlı olarak yürümesini sağlıyor. Şartları belirleyen şey ise daha evvelden tanıdığımız flag'lar. Flag'lardan yalnızca dört tanesi için bir karar verme olayı söz konusudur. Bunlar: Z-flag'ı (Zero), N-flag'ı (Negative), C-flag'ı (Carry) ve V-flag'ıdır (Overflow). Şartlı programlama; şarta göre programın belli bir adrese dallanması biçiminde oluşur. Her bir flag için ikişer adet şartlı dallanma komutumuz mevcut. Birinci komut grubu şayet flag yanıksa (içeriği “bir” ise) dallanıyor; ikinci gruptakiler ise flag sönükse (içeriği “sıfır” ise) dallanıyor. Şimdi bir olaya geri dönelim; şayet şart gerçekleşmezse hiçbir şey olmadan program devam edecek, fakat şart gerçekleştiğinde ise program belli bir adrese dallanacak. Peki bu belli adres neresi?.. Dikkatlice bakıldığında bu adresin söz konusu komutların hemen arkasından bir operand olarak belirtilmesi gerektiği ortaya çıkar. En basit çözüme örnek olarak, onaltı bitlik adresin hemen komutun arkasından gelmesi verilebilir. Böylece her bir şartlı dallanma komutu (branch) içeren satır üç byte sürecekti. Fakat ana işlem ünitemizin tasarımını yapan akıllı mühendisler daha pratik bir çözüm bulmuşlar. Bir programın dallanması genelde kısa bir mesafe içinde olduğu için yeni bir adresleme tipi geliştirilmiş: Relatif Adresleme. Bu adresleme tipinde yapılacak adres onaltı bit'lik absolut adresi ile değil, o adresin program sayacına olan uzaklığı ile belirtiliyor. Bu uzaklık ise yalnızca sekiz bit'lik bir değer ile temsil ediliyor. Daha evvelden de bildiğimiz gibi sekiz bit'lik bir bilgi ile 256 değişik sayıyı temsil edebiliriz. En basit düşünce ile 256 byte ileri dallanabiliriz. Fakat çoğu zaman geriye dallanmak da gerekebilir. Örneğin: Bir döngünün başına. Bu yüzden sekiz bit'lik bir bilgiden negatif değerler de elde edebilmemiz lazım. Bunun için şöyle bir yöntem kullanılıyor: 7'nci bit'in değeri 128 değil -128 olarak değerlendiriliyor. Yani bir bakıma yedinci bit sayımızın işareti ile ilgili bilgiyi de taşıyor. Aslında bu yöntem ile ilgili birçok örnek vermek mümkün. Fakat bütün bunların hiçbiri aşağıdaki gösterim kadar açıklayıcı olmayacaktır:
10000000 $80 -128 10000001 $81 -127 $FE -2 $FF -1 00000000 $00 0 00000001 $01 1 00000010 $02 2 $7E 126 $7F 127
Şimdi 7'nci bite baktığımızda görüyoruz ki, bu bit bir sayının negatif olup olmadığını belirliyor (Aynı zamanda N-flag'ın görevi). Şimdi bir örnekle relatif adreslemede adres farkını hesaplamayı görelim. Dallanma sırasında program sayacının içerdiği bir sonraki komutun adresi olur. Örneğimiz şu: Şartlı dallanma komutumuz
$C47A adresinde duruyor ve biz $C4BF adresine dallanmak istiyoruz.
$C47A Şartlı dallanma komutunun adresi $C47C Bir sonraki komutun adresi $C4BF Varış adresi
Şimdi basit bir çıkartma işlemi bize varış ile çıkış adresi arasındaki farkı verecektir:
$C4BF - $C47C = $43 Yani şartlı dallanma komutumuz için operand byte'ımızın değeri $43'müş. Bir örnekle de geriye doğru sıçramayı inceleyelim. Diyelim ki $C440 adresine dallanacağız. Burada farkı belirlemek için değişik yöntemler söz konusu. İlk yöntem bildiğimiz çıkartma işlemi, fakat sonuçta negatif bir sayı elde ediyoruz. $C440 - $C47C = $FFC4 (elde var) Elde ettiğimiz sonucun düşük değerli byte'ı yani $C4 işimizi görecektir, o'nu operand olarak kullanabiliriz. Diğer bir yöntem ise pozitif çıkartma işlemini yapmak ve ikili eşleniğini (komplementini) bulmak.
$C47C - $C440 = $3C Bunun ikili eşleniği:
9900111100 9011000011
1
011000100 $C4
Gördüğünüz gibi gene $C4 değerini elde ettik.
Relatif adreslemenin bize sunduğu avantajlara gelelim: Öncelikle üç byte
A yerine iki byte kullanarak belli bir ölçüde hafızadan tasarruf ediyoruz. (Bazılarınız bu tasarrufu küçümseyebilir. Fakat şöyle bir açıklama kuşkuları giderecektir. Coğu compiler'ın ürettiği kod'da bu komutlar o kadar yoğundur ki bu komutlar üç byte'lık olsaydı program 05 ila 707 uzayacaktı.) Relatif adreslemenin en önemli avantajı absolut değerler içermemesidir. Adresler çıkış yerine bağıl (izafi) uzaklıklarına göre belirtilir. Şayet bu program parçasını hiç değiştirmeden başka bir bölgeye taşırsak çıkış ve varış komutları arasındaki fark değişmeyecektir (Fakat absolut adresler değişecektir). Şayet absolut adres kullanmış olsaydık bu adreslerin de kaydırma işlemi sonunda yeni baştan elden geçirilmesi gerekirdi. Halbuki relatif adreslemede böyle bir sorun olmadığı için üretilen program “transportable'- dır, yani başka bir bölgede de çalışabilir. (Tabii bu ölçü programın içinde kullanılan diğer programlama yöntemlerine de bağlıdır.) Relatif adreslemenin dezavantajlarına bakarsak tek dezavantajın sınırlı adresleme kapasitesi olduğu görülür. Şartlı dallanma komutuna göre 128 byte öne veya 126 byte geriye sıçrayabiliyoruz. Pratikte bu durum pek sorun teşkil etmez. Nedeni ise daha uzun mesafelere sıçrama gereksiniminin pek az meydana çıkması. Eğer relatif adreslemede operand hesaplamayı çok karışık bulduysanız, size sakin olmanızı tavsiye ederiz. Çünkü hemen hemen hiçbir zaman bu operand'ı siz hesaplamayacaksınız. Kullanacağınız tüm yardımcı programlar (gerek monitör programı, gerek assembler programı) bu işi üstlenirler. Siz bu komutları kullanırken sadece varış adresini verirsiniz, o program da o adresin izin verilen bölge içinde olup olmadığını kontrol eder, şayet mümkün değilse sizi uyarır. Eğer mümkünse gerekli kodu üretir ve işleme devam eder. Şimdi bu dört flag'a göre şartlı dallanma komutlarını görelim:
Zero flag'ına göre dallanma
Zero flag'ı yanık olduğu durumda dallanmak istiyorsak “branch on egual” komutunu kullanmamız gerekir, kısaltılmışı BEO. Zero flag'ı sönükken dallanmak istiyorsak “branch on not egual” komutunu kullanacağız, kısaltılmışı BNE.
Carry flag'ına göre dallanma
Carry varsa dallanmak için “branch on carry set” yani BCS komutunu, carry yokken dallanmak için ise “branch on carry clear” yani BCC komutuni kullanmamız gerekmektedir.
Negative flag'ına göre dallanma
N-flag'ı yanıkken sıçramak için on minus' yani BMI komumutunu kullanmamız gerekmektedir. “branch on plus' yani BPL komutunu kullanmamız gereklidir.
Overflow (taşma) flag'ına göre dallanma
Taşma varken dallanmak için *branch on overflow set” yani BVS komutunu taşma yokken dallanmak için BVC komutunu kullanmamız gerekir. Bu gruptaki komutlar genelde diğerlerine göre daha seyrek kullanılır. Aşağıdaki tabloda tüm şartlı dallanma komutlarını ve kod'larını bulacaksınız.
Komut Komut kodu $FO BNE $DO BCS $BO . BCC $90 BMI $30 BPL $10 BVS $70 BVC $50
8. Sıçrama Komutları
Bir önceki bölümde gördüğümüz şartlı dallanma komutlarının tersine belli bir (absolut) adrese giden komutlara sıçrama komutları denir. Bu komutlar herhangi bir şarta bağlı değildir ve her seferinde yürütülürler. Sıçrama komutları absolut adresleme ile kullanıldığı gibi daha evvelden kısmen tanıdığımız başka bir adresleme tipine de sahiptir. İndirekt adreslemeli sıçrama. Bu komutun hemen arkasından gelen adres varış adresi değildir. Bu adres, varış adresini gösteren bir göstergecin adresidir. Burada varış adresi peşpeşe gelen iki Byte'ta daha evvelden tanıdık olduğumuz göstergeç formatında (Lo-Byte, Hi-Byte) bulunur. Bir örnekle görelim:
JMP ($0302) $0302'deki göstergeç üzerinden indirekt sıçrama.
Bu emir yürütülürken varış adresi $0302 ve $0303 adreslerinin içeriğinden oluşturulur. Diyelim ki orada $40 ve $C8 bulunsun, böylece programımız $C840 adresine sıçrar ve oradan devam eder. Bu adresleme tipi yalnızca JMP komutuna aittir. Varış adresi olarak aletinizin mümkün olan tüm adreslerini belirtebilirsiniz. Aşağıdaki tabloda her iki komutun adresleme
- tiplerini ve emir kodlarını bulacaksınız: Adresleme tipi JMP absolut $4C indirekt $6C
COMMODORE 64'ün işletim sisteminde indirekt adresleme tipi oldukça yoğun şekilde kullanılmıştır. Hafızanın üçüncü sayfasında $0300 adresinden, $0330 adresine kadar sistem vektörleri yer almaktadır. Bu vektörlerin RAM'de bulunmasının oldukça fazla avantajları vardır. En basit örnek olarak bu vektörleri değiştirerek işletim sistemi ile ortak çalışan programlar yazabilme olanağı. Böylece bilgisayara yeni bir özellik kazandıracak programlar yazmak çocuk oyuncağı kadar basit bir olay haline geliyor.
9. Sayma Komutları
Döngüler ve sayaçlar içeren kuvvetli programlama tekniklerini kullanabilmek için 6510'un özel sayma komutları vardır. Bu komutlar sayesinde gerek register, gerek hafıza birimlerinin içeriğini bir artırabilir veya bir eksiltebiliriz. Artırma komutları fonksiyon bakımından BASIC'teki NEXT komutuna benzer. Eksiltme komutlarında ise komutu ile çalışıyormuş gibi düşünün.
INX
Bu komutla X-register'ının içeriği bir artırılır. Sonuca göre N- ve Z-flag'larının içeriği değişir. BASIC'te bir örnek verecek olursak:
X-—X-41
Diyelim ki artırmadan önce X-register'ının içeriği $FF olsun. Değer olarak 256'yı gösteremeyeceğimiz için gene sıfıra döneriz. Yani kısacası X-register'ine bir toplanıyor. Fakat bu toplama sırasında C-flag'ı göz önüne alınmıyor ve sonucunda 255 geçilince C-flag'ı da etkilenmiyor. Bu örnekte sonuç olarak sıfır elde ettiğimiz için Z-flag'ı yakılır.
INY
Bu komut Y-register'ini bir artırmak için kullanılır ve Y-register'inin kullanılması dışında geri kalan her şey yukarıdaki komutla aynıdır. Bu komutun BASIC'te benzeri:
Y-Y*41
COMMODORE 64'ün ana işlem ünitesi 6510, akümülatör'ün içeriğini tek komutta bir artıran bir komuta sahip değildir.
INC
Bu komut belli bir adresteki byte'ın içeriğini bir artırmaya yarar. Sonuca göre N- ve Z-flag'ları etkilenir. Bu komutun şimdiye kadar gördüğümüz diğer komut gruplarından farkı, belli bir hafızanın içeriğinin önce ana işlem ünitesinin içine okunması, orada bir artırılması ve tekrar yerine yazılmasıdır (Read-Modify-Write). Şimdiye kadar gördüğümüz komutlar ise bir hafızanın içeriğini ya okuyor, ya da yazıyordu; hiçbiri ikisini birden yapmıyordu. INC komutu yürütülürken akümülatör'ün, X-register'inin ve Y-register'inin içeriği değişmez. BASIC'te bu işi yapan satırı şöyle yazarız:
POKE M, PEEK(M) 4 1
Burada M, artırılacak hafızanın adresini göstermektedir.
Şimdi hafıza ve register'leri bir eksilten komutları görelim.
DEX
Bu komut X-register'inin içeriğini bir eksiltir. Sonuca göre N- ve Z-flag'ları etkilenir. Diyelim ki X-register'inin içeriği $00'dı ve biz eksilttik. Bu durumda $FF elde ederiz ve hiçbir şekilde Carry flag'ı etkilenmez. BASIC'te aynı işi yapan satır şöyle olacaktır.
X-X-I
Tabii negatif sayı diye bir şey söz konusu olmayacaktır.
DEY
Bu komut Y-register'inin içeriğini bir eksiltir. DEX komutu için söylenenler aynen geçerlidir. BASIC'te aynı işi yapan satır:
Y=Y-1 Burada da $00'dan $FF'e geçeriz. DEC
Bu komut belli bir adresteki hafıza biriminin içeriğini bir eksiltmeye yarar. Bu işlem sırasında akümülatör'ün içeriği kesinlikle etkilenmez. INC komutu için söylenenler aynen geçerlidir. Aşağıda komutları, adresleme tiplerini ve komut kodlarını bulacaksınız.
Komut Komut kodu
INX $E8 INY $C8 DEX $CA DEY $88 Adresleme tipi INC DEC absolut $EE $CE absolut X-indeksli $FE $DE 0. sayfa X-indeks $F6 $D6 10. Flag'ları Değiştirme Komutları
Flag'ların durumuna göre programın akışını değiştiren komutlardan başka, kullanıcının flag'ları istediği biçimde değiştirmesini sağlayan komutlar da mevcuttur. Daha evvel de örneklerini gördüğümüz gibi; toplama ve çıkarma işlemlerinden önce bu tip komutları kullanıp C-flag'ının durumu belirlenmelidir. Bu gruptaki komutlar operand'a ihtiyaç göstermezler ve bir Byte'a sığarlar.
Carry flag'ı
SEC (“set carry”) komutu ile C-flag'ı yakılır. CLC (“clear carry”) komutu ile de C-flag'ı söndürülür. SEC komutu her çıkartma işleminden önce, CLC komutu ise her toplama işleminden önce kullanılmalıdır, yoksa yanlış sonuçlar elde ederiz. Tabii birkaç byte genişliğindeki bilgileri toplayıp, çıkarıyorsak ara işlemlerde C-flag'ı ile oynamayın, çünkü C-flag'ı, byte'ların birbirine birleşmesi sırasında gerekli bilgileri içerir. Carry flag'ı yalnızca ilk toplama veya çıkarma işleminden önce belirlenmelidir.
Decimal flag'ı
Bu flag toplama ve çıkarma işlemlerinin bildiğimiz ikili sistemde mi, yoksa ikili kodlanmış ondalık sistemde mi (Binary Coded Decimals, BCD) yapılacağını belirler. BCD modunda işlem yapabilmek için C-flag'ının yanık olması gerekir. Konuya yeterince hakim olmadıkça bu modu kullanmanızı pek tavsiye etmeyiz. Daha ileride yayınlayacağımız “PROGRAMLAMA TEKNİKLERİ” bölümünde, bu modun detaylarını açıklayıp örnek bir program geliştireceğiz. O zamana kadar sabır!.. D-flag'ını yakmak için SED (“set decimal”) komutunu, bu flag'ı söndürmek için ise CLD (“clear decimal”) komutunu kullanacağız.
Interrupt flag'ı
Interrupt denilen olay, programın yürürken, herhangi bir (hardware) donanımın gönderdiği sinyal yüzünden kesilmesi, özel bir program parçasının yürütülmesi, daha sonra da kesilmiş olan programa hiçbir şey yokmuş gibi olduğu gibi geri dönmesidir. Aslında yukarıdaki uzun cümle olayın çok basit bir özetidir. Daha ileride bu olaya çok daha detaylı olarak eğileceğiz. Interrupt flag'ı interrupt'a izin verilip verilmediğini belirler. I-flag'ını yakmak için SEI (“set interrupt disable”) komutunu kullanırız ve durum da interrupt'a izin verilmez. Interrupt'a tekrar izin vermek için I-flag'ı söndürülmelidir. Bunun için CLI (“clear interrupt disable”) komutu kullanılır.
Overflow flag'ı
Overflow flag'ı sadece söndürülebiliyor (Çünkü yakmanın pek bir anlamı yok). Bu işi yapan komut ise CLV (clear overflow). COMMODORE 64'ümüzün ana işlem ünitesi 6510'da bulunmayan, fakat 6502 ana işlem ünitesinde bulunan bir özellikten bahsedelim. Bu flag aynı zamanda ana işlem ünitesinin bir bacağına uygulanan bir sinyal tarafından da yakılabiliyor. Yani programdan bağımsız da etkilenebiliyor bu flag. Tekrar yakılabilmesi için söndürülmesi gerektiğinde CLV komutu kullanılıyor. Bilhassa 1541 Disk-Drive'de çok kullanılan bu özelliğe yazımızın ilerleyen bölümleriyle değineceğiz. Aşağıdaki tabloda komutları ve komut kodlarını bulacaksınız.
Komut Komut kodu CLC $18 SEC $38 CLD $D8 SED $F8 CLI $58 SEI $78 CLV $B8
11. Bit Kaydırma Komutları
6510 ana işlem ünitemizin yürüttüğü başka bir komut grubu daha var ki, bu gruptaki komutlara karşılık gelen BASIC komutları yok, bu grup bit kaydırma komutlarını içeriyor. Sözkonusu işlem sırasında akümülatör'ün, ya da adreslenen hafıza biriminin bit yapısı bir bit sağa veya sola kaydırılır. Şayet kaydırılan şey akümülatör ise, akü adreslemesinden söz ediyoruz. Bu gruptaki komutlar adresleme tipine göre bir, iki, ya da üç byte uzunluğunda olabiliyor. Şayet adresleme tipi bir hafıza elemanını gösteriyorsa, aynen INC ve DEC komutlarındaki oku-değiştir-yaz (Read-Modify-Write) işlemleriyle komut yürütülür. Bu işlem sırasında akümülatör'ün içeriği korunacaktır.
ASL
ASL, anlam olarak “arithmetic shift left'in baş harflerinden oluşmuş bir kısaltmadır. Yapılan işlem şudur: Adreslenen byte'ın içeriği bir bit'lik pozisyon olarak sola kaydırılır. Sıfırıncı bit'in yeri boş kalacağı için oraya “0” yazılır. Yedinci bit'teki bilgi ise dışarda kalır. O da Carry'ye alınır. Diyelim ki akü ile bu işi yaptık. Bir örnekle görelim:
ASLA Akü $47 içersin
001000111
9010001110 $8E, C-0
Bu örneğimizde sonuç olarak akümülatör'ün içeriği olarak $8E elde ettik ve Carry bit'i (flag'ı) söndürüldü, çünkü kaydırmadan önce akümülatör'ün 7'nci bit'i “0” içeriyordu. Akümülatör'ün kaydırmadan önce ve sonraki içeriklerini karşılaştırırsak görürüz ki akümülatör'ün içeriği iki katına çıkmış. Durumu daha iyi kavrayabilmek için ondalık sistemde düşünelim. Şayet ondalık bir sayıyı bir basamak sola kaydırırsak değeri on katına çıkar. Aynı olayın ikili sistem için de geçerli olduğunu gözönünde bulundurursak, demin elde ettiğimiz sonucun rastlantı olmadığını görürüz. Yani ASL komutu ile bir sayıyı iki katına çıkarabiliriz. Bir örnek daha inceleyelim.
ASL A Akü $CD içersin $CD %011001101 %110011010 $9A, C=1
Carry flag'ını işlemin sonucunda sol taraftaki ekstra bit olarak görürsek, gene sayımızın değerinin iki katına çıktığı sonucuna varırız. $CD (205)'in iki katı $19A (410)'dur.
#
5 e te |
LSR
LSR komutu “logical shift right”-ın kısaltılmışı olup, ASL komutunun tersi işlemi yapar. Burada byte'ın içeriği sağ tarafa kaydırılır. 7'nci bit'e “0” yüklenir. Dışarı çıkan 0'ncı bit ise Carry'e alınır. Bir örnekle görelim:
LSR A Akü $CA içersin $CA %011001010 %001100101 = $65, C=0
Sonuç olarak akümülatör'de $65 ve sönük bir Carry bit'i elde ettik. Sizin de dikkatinizi çektiği gibi akümülatör'ün değeri yarıya indi. Carry bit'i kaydırmadan önceki sıfırıncı bit'in kopyasını içeriyor, başka bir deyişle Carry bit'i ikiye bölme sırasında artan olup olmadığını gösteriyor. Böylece bir sayının tek mi, çift mi olduğunu belirleyebiliriz. LSR en alttaki bit'i Carry'ye çıkarır, böylece BCC ve BCS komutları ile dolaylı olarak en alttaki bit'i test edebiliriz. Eğer LSR komutu bir hafıza elemanını adreslerse akümülatör'ün içeriği değişmez.
ROL
ROL komutu “rotate left'in kısaltılmışından gelir ve bit'lerin içeriğini ise dizilmiş boncukları kaydırır gibi döndürür. Sola kaydırma sırasında boşalan sıfırıncı bit'in yerine Carry bit'i kopya edilir. Dışarı çıkan yedinci bit'in içeriği ise Carry bit'ine alınır. Daha genel bakarsak, yapılan işlem dokuz bit'lik bir bilginin kendi içinde döndürülmesidir (Byte'a ait 8 bit ve Carry bit'i). Bir örnek daha iyi kavramımızı sağlayacak: ROL A Akü $4B içersin Carry yanık olsun $4B %001001011 C=1 %010010111 $97
Bütün bit'ler bir basamak sola kaydı. Carry bit'i boşalan sıfırıncı bit'in yerine geldi. Dışarı çıkan yedinci bit Carry'ye alındı. Sonuç olarak $97 ve sönük bir Carry elde ettik. Burada da akünün değerinin iki katına çıktığını, fakat bundan başka mesela daha evvel oluşmuş bir eldenin veya daha evvelki bir kaydırma işleminden çıkmış Carry bit'inin de toplandığını görüyoruz. Bu son yorum oldukça ilgi çekici, çünkü Carry bit'i yalnızca toplama ve çıkarmada değil, aynı zamanda sağa ve sola kaydırmalarda birkaç byte'ı birbirine bağlamak için kullanılan bir ara değer taşıyıcısı durumunda bulunuyor.
ROR
ROR komutu (rotate) ROL komutunun tam tersi işlemi yapar. Bu sefer bit'lerin dönüş yönü sağa doğrudur. Bir örnekle görelim: ROR A F Akü $89 içersin Carry sönük olsun $89: %10001001 C=0 %01000100 C=1
Akümülatör'ün içeriği olarak $89'dan $44 elde ettik. Carry'nin yanık olması bölme işleminde artan olduğunu gösteriyor. Kaydırma komutlarında Carry Flag'ından başka sonuca göre N- ve Z-flag'ları da etkilenir. Aşağıdaki tabloda komutları ve adresleme tiplerini bulacaksınız.
Adresleme tipi ASL LSR ROL ROR akü $0A $4A $2A $6A absolut $0E $4E $2E $6E
0.cı sayfa $06 $46 $26 $66 absolut X-indeksli 0.cı sayfa X-indeks $16 $56 $36 $76
$1E $5E $3E $7E