Makine Diline Merhaba (2)
Retro bilgisayarMEHMET ULUSEL
Komutları ve Adresleme Tipleri
Ana işlem ünitemizin komutları için 256 ihtimal olduğunu belirtmiştik. Fakat bu 256 ihtimalden 151'i komut olarak tanımlanmıştır. Gene de bu rakam gözünüzde büyümesin. Çünkü bunların çoğu bir grup altına giriyor ve adresleme tiplerinde farklılaşıyorlar. 6510'un birbirlerinden tümüyle farklı olarak 56 komutu var. Bizim genel kanımız ise bu komut setini kolayca öğrenebileceğiniz yönünde. Şimdi size bu komutları daha genel kategorilerde toplayıp anlatacağız. Bu arada sırası geldikçe adresleme tiplerini örneklerle açıklamaya çalışacağız.
1. Yükleme Komutları:
Bu komutlar ana işlem ünitesinin registerlerine (yazmaçlarına) verileri almaya veya yüklemeye yarıyor. Ana işlem ünitesinin üç adet register'i olduğu için bunlara ait yükleme komutları da kalıplaşmış durumda. Bunlar:
Akümülatör'e yükle
LDA - LDX — X-Register'ine yükle LDY — Y-Register'ine yükle
Böylece üç komutu öğrenmiş olduk. Kaldı elliüç! Bu komutları örneklerle açıklarken aynı zamanda adresleme tiplerini de kullanacağız. Adresleme tipi, ana işlem ünitesinin söz konusu verinin adresine nasıl ulaştığını belirtir. Biz örnekleri verirken daha anlaşılır olması açısından o işi görecek BASIC komutunu da vereceğiz. Böylece kavramların daha iyi yerleşeceği kanısındayız. İlk inceleyeceğimiz adresleme tipi direkt adresleme (immediate addressing mode):
LDA y£ SOA
10 olarak)
Bu adresleme tipinin karakteristik belirleyicisi, yüklenecek değerin hemen önünden gelen # işaretidir. Direkt adresleme akümülatör'ün doğrudan $0A (onaltılık olarak $0A) değeriyle yükleneceğini gösterir. Bu işe karşılık gelen BASIC komutu ise:
0
Bu adresleme tipi herhangi bir register'e sabit bir değeri yüklemek için kullanılır. Bu adresleme tipi X- ve Y- Register'leri için de vardır. Bunlara örnek olarak:
LDX
LDY $AB
verebiliriz. Burada X-Register'i $7F (ondalık olarak 127) değeriyle, Y-Register'i $AB (ondalık olarak 171) değeriyle yüklenir. Bu adresleme tipinde aynı zamanda yüklenmesi gereken değer de makine dili programın bir parçası haline gelir. Hafızada komut ve yüklenmesi gereken değer peşpeşe Byte'lar olarak durur. Makine dili programı bu adreste yürürken bu Byte'ı alır ve bunu bir komut olarak yorumlar. Diyelim ki komut olarak $A9'a (ondalık olarak 169) rastladı; ana işlem ünitesinin içindeki karmaşık devreleri hemen bunun bir LDA #$.. komutu olduğunu algılar. Aynı karmaşık devreler bu sefer de bir sonraki Byte'ın komut değil de veri olacağına karar verirler. Bir sonraki Byte okunur ve değeri akümülatör'e yüklenir. Burada gördüğünüz gibi bu işlem toplam olarak iki Byte sürüyor (komutun kendisi bir Byte; yüklenecek veri diğer Byte olmak üzere). Ana işlem ünitesi bir komutun başlangıcından, bu komutun bitimine, bir sonraki komutun başına kadar program sayacının değerini otomatik olarak iki artırır. İkinci olarak absolut adresleme tipini inceleyelim. Bu adresleme tipi register'e sabit bir değer değil de, bir hafıza biriminin (adreslenebilir bir Byte'ın) içeriğini yüklemek için kullanılır. Örnek verecek olursak:
LDA $COAF
Burada akümülatör'e $C0AF adresinin içeriği yüklenir. Şimdi ufak bir sorun çıkıyor. Bu işlem hafızada nasıl yerleşmekte?.. $C0AF adresi 16-bitlik bir sayıdır ve bu özelliğinden dolayı bir Byte'a sığmaz. Hemen herkesin aklına gelen çözüm pratikte de gerçekleşiyor ve 16-bitlik bu sayı 8-bitlik iki sayıya bölünüp hafızaya öyle yerleştiriliyor. Bu arada 65XX serisi ana işlem ünitelerinde geçerli olan bir kuralı hatırlatalım: Önce düşük basamaklı Byte, peşinden yüksek basamaklı Byte geliyor. Yani 16-bitlik bir sayının önce sağ tarafı, sonra sol tarafı yazılıyor. Şimdi bu işlem hafızada nasıl görünür, bir inceleyelim. Önce LDA komutunun bu adresleme tipine karşılık gelen kod'u $AD (173), daha sonra $AF (175) ve son olarak $C0 (192) gelir. Aynı işlemi yapan satırı yazmak istersek:
Az
$COAF
Tabii ki aynı komutun X- ve Y-Register'leri için karşılıkları var. Bunlar için ayrı bir örnek vermeyeceğiz. Çünkü akümülatör'le yapılan işlemden farklı bir şey yok. Diyelim ki ana işlem ünitesi bu işlemi hafızada yürütüyor. Önce komutu tanır, arkasından adresin düşük değerli kısmını (Lo-Byte da denir) okur, onun arkasından adresin yüksek değerli kısmı (Hi-Byte da denir) gelir. Şimdi ana işlem ünitesi tüm bir satırı okudu. Ne yapacağını biliyor, fakat henüz hiçbir şey yapmamış durumda. Burada ana işlem ünitesi kısa bir süre programın kendisinden ayrılır ve adreslemesi gereken bölgeyi adresleyip oranın içeriğini alır ve akümülatör'e yükler. Görüldüğü gibi bu işlem tipi üç Byte sürmekte. Yani bu işlem bittiğinde program sayacının değeri üç artacaktır. Şu ana kadar iki ve üç Byte süren komutları gördük. Bunlardan başka bir de bir Byte uzunluğundaki komutlar var ki bunlar genelde ana işlem ünitesinin içini ilgilendiren veya başka bir deyimle herhangi bir operand'a gereksinim duymayan komutlardır. Burada, birinci bölümde andığımız durum register'inden söz edelim. Yükleme komutları sırasında N (negative) ve Z (zero) flag'ları etkilenir. Diyelim ki örneğimizdeki gibi akümülatör'e $0A yükledik. Bu sayı sıfır olmadığı için Z flag'ı sönük (=0) olacak; bu sayının yedinci biti sönük olduğu için N flag'ı sönük olacaktır. Başka bir adresleme tipi de sıfırıncı sayfa adreslemesidir. Bu adresleme tipi yapı bakımından absolut adreslemeyle eşdeğerdir. Fakat geçerli olduğu adres bölgesi hafızanın ilk 256 byte'ıdır. Bu adres bölgesi $0000'dan $00FF'a kadar gider. Dikkat ettiyseniz, adresin yüksek değerli Byte'ı sıfır değerindedir. Sıfırıncı sayfa ismi de buradan gelmektedir. Açıkça görülmektedir ki bu adresleme tipinde aynı işlem için absolut adreslemeye göre bir Byte tasarruf ediyoruz. Böylece bu işlem hafızada daha az yer tutacağı gibi, aynı zamanda ana işlem ünitesi tarafından belli bir miktar daha hızlı yürütülür. Dezavantaj olarak sınırlı adres bölgesi görünmekle birlikte, avantajlar daha ağırlıktadır. Çünkü bilgisayarımızın önemli sistem değişkenleri (işletim sisteminin bilgisayarı hayatta tutmak için kullandığı hafıza bölgesi) bu bölgede saklanmaktadır. Bir örnek verecek olursak:
LDA $73
Bu işlem hafızaya iki Byte olarak yerleşecektir. Bunlar komutun kendisi olan $A5 (165) ve adresi gösteren $73 (115)'tir. Bu işlemi BASIC'te yazmak istersek:
$73
Tabii BASIC'te vereceğimiz karşılaştırmalı örnekler açısından absolut adresleme ile sıfırıncı sayfa adresleme arasında bir fark görünmeyecektir. Bu arada aklımıza gelmişken bir şeyi hatırlatalım: Sıfırıncı sayfa ile ilgili adreslemeleri, isterseniz absolut adreslemeler ile de yapabilirsiniz. Hiçbir engel yok, fakat size sağlanan avantajı kullanmamakla programınız uzar ve biraz yavaşlar. Önemli bir adresleme tipi de indeksli adreslemedir. Burada X- ve Y- indeks registerlerinin asıl önemini daha iyi kavrayacağız. Bilhassa makine dilindeki özel döngülerde çok kullanılan bu adresleme tipine örnek verecek olursak:
LDA $25B8,X
Burada ilk bakışta görünen absolut adreslemenin indeksleme ile birlikte yapıldığı. Peki gerçekte ne oluyor?.. Gayet basit: Ana işlem ünitesi $25B8 adresini oluşturduktan sonra hemen bu adresin içeriğine saldırmıyor. Önce bu adrese X-Register'inin içeriğini topluyor; yeni bir adres oluşturuyor. Bu adresin içeriğini akümülatör'e yüklüyor. Diyelim ki X-Register'inin içeriği $35. Şimdi ana işlem ünitesinin içinde şöyle bir aritmetik işlem yapılıyor:
$25B8 + $35 = $25ED
Yani sonuç olarak akümülatör'e $25ED adresindeki yazmaçın içeriği yükleniyor. Programın bu bölgesi her defasında değişik bir X- değeriyle yürütülürse elde edilen adres farklı olacağı için her defasında farklı bir değer yüklenecektir. Bu adresleme tipi bilhassa döngülerde ve veri tablolarının işlenmesinde kullanılır. Mesela bir şifreleme tablomuz ve bir şifre çözücü tablomuz olsun, bu ikisi sayesinde bu karışık işlemleri, indeksli adreslemeyi kullanarak basit işlemlerle yerine getirebiliriz. Daha ilerde başka uygulama örnekleri de göreceğiz. BASIC'te bu işlemi yapan satır şöyle bir şey olacaktır:
$25B8
Buradaki X, X-registerinin içeriğini; A'da akümülatör'ü simgelemektedir. İndeksleme işleminde X-registerinin yerine Y-registerini de kullanabiliriz. Örneğin:
25B8,4
LDA
Burada ise Y-register'inin içeriği adrese toplanır ve esas adres oluşturulur. Mesela; böylece birbirinden bağımsız iki döngü değişkenimiz olur ve içiçe geçmiş döngüler kurabiliriz. Sıfırıncı sayfanın da kendine özgü indeksli adresleme tipi vardır. Burada sıfırıncı sayfa adreslemesinin avantajlarının yanında indeksleme işlemini de kullanabilmemiz sağlanır. Bir örnek olarak:
LDA $BA,X
Bu da iki Byte'lık bir komut olacaktır. Şimdi geliyoruz; değişik ve kullanışlı olduğu kadar anlaşılması zor olan bir adresleme tipine, indirekt indekslemeli adresleme. Bu adresleme sıfırıncı sayfanın özelleşmiş bir kullanımı olduğu için sıfırıncı sayfanın önemini daha iyi anlayacağız. Sıfırıncı sayfada peşpeşe gelen iki Byte'ın içeriği bir adres oluşturuyor, daha sonra bu adrese Y-register'i toplanıyor ve esas adres oluşturuluyor. Çok mu karışık?.. Peki, bir örnekle görelim:
LDA ($70),Y
Diyelim ki, $0070'in içeriği $20; $0071'in içeriği $C8 olsun. Bu ikisi birlikte $C820 adresini oluştururlar. Hemen arkadan Y-register'inin indeksleme işlemi geliyor. Diyelim ki Y-register'inin içeriği de $B3. Böylece bu değeri de adresimize toplayarak $C8D3 adresini elde ederiz. Bu adresin içeriği (diyelim ki $C8D3'ün içeriği $4F olsun); akümülatör'e yüklenir. Şematik olarak inceleyecek olursak:
LDA ($70),Y
(870) $20
(871) sC8
$C820
m- $B3
$C8D3
(SC8D3)- $4F
Bu değer de akümülatör'e yüklenir. BASIC'te bu işlemi şöyle yaptırırız:
A-PEEK(PEEK 4112)4256*PEEK(113)4 1)
sT0 si
İndirekt adresleme operand'ın parantez içinde yazılmasıyla ayırt edilir. Bu adresleme tipi çok güçlü program yapılarının kurulmasını sağlar. Çünkü iki Byte süren bir işlemle bütün hafıza elinizin altında. Bu adresleme tipi de döngülerde ve tabloların değerlendirilmesinde kullanılır. Basit indekslemeden daha esnek ve güçlüdür. Çünkü yalnızca bir sayfayı (256 Byte'lık bölge) değil tüm hafızayı işleyebiliyorsunuz. Tabii bu işlemleri yapabilmek için sıfırıncı sayfada iki Byte'lık bir göstergeç hazırlamak gerekiyor. Son olarak indekslemeli indirekt adreslemeyi göreceğiz. Bu tip yukarıda anlattığımızın tersine Y-register'i ile değil X-register'i ile yapılıyor. Genelde kullanımı ötekine göre daha az olan bu adresleme tipinde de sıfırıncı sayfada bir göstergeç bulunuyor. Bu göstergeç esas adresi içeriyor. İndeksleme işlemi ise sıfırıncı sayfa içinde bu göstergecin yerini bulmak için yapılıyor. Daha anlaşılır olması için gene bir örnek üzerinde çalışalım:
LDA (70,X)
$08
840
(879)- 820
$2040
(82040)- SA9
Bu değer de akümülatör'e yüklenir. BASIC'te bu satırı şöyle yazarız:
AzPEEK(PEEK(1124 1)
1
Demek ki burada önce X-değeri operand'a toplanıyor ve göstergecin adresi elde ediliyor. Bu göstergecin içeriği alınarak esas adres elde ediliyor ve bu adresten akümülatör'e yükleme işlemi yapılıyor. Bu adresleme tipi pek ender kullanılır ve pek kullanışlı olacağı da şüphelidir. Bu yüzden başlangıçta bu adresleme tipine pek önem vermeyeceğiz. Şimdiye kadar gördüğümüz komutları ve adresleme tiplerini toplu olarak görelim:
Adresleme tipi LDA LDX LDY direkt $A9 $A2 $A0 absolut $AD $AE $AC sıfırıncı sayfa $A5 $A6 X-indeksli $B0 — $BC Y-indeksli $B9 $BE — 0'cı sayfa X-indeks — — $B4 0'cı sayfa Y-indeks — — — — indirekt indeksli sı — — $A1 indeksli indirekt
2. Saklama Komutları
Saklama komutları, yükleme komutlarının tam tersi işlemi yaparlar. Bu komutlar yardımıyla bir register'in içeriğini hafızanın belli bir adresine yazabiliriz. Bu işi yapan komutlar şunlardır:
STA STX STY larınız değişmez. Saklama komutundan önce ne ise, aynı şeklini korur. Aşağıdaki listede bütün komut kodlarını ve geçerli adresleme tiplerini bulacaksınız.
Adresleme tipi STA STX STY absolut $8D $8E $8C sıfırıncı sayfa — $86 X-indeksli $9D $9E $9C Y-indeksli $99 — — 0. sayfa X-indeksli — — — $94 0. sayfa Y-indeksli — — — — indirekt indeksli sı — indeksli indirekt sı —
Yapılan işlemleri BASIC'te, POKE komutunu kullanarak yapacağız. Bu komut hafızadaki herhangi bir elemana ulaşıp onun içeriğini değiştirmemizi sağlar. Adresleme tipleri elemanın adresini elde ederken uygulanan farklı yöntemleri gösterir. Birkaç örnek verelim:
MEHMET ULUSEL.
Bu komutlar görüldüğü gibi akümülatör'ün (aynı şekilde X-register'inin, ya da Y-register'inin) içeriğini hafızanın belli bir adresindeki elemanda saklamamıza yarar. Kullanabileceğimiz adresleme tipleri, tek eksik dışında, yükleme komutları ile aynıdır. Bu eksik adresleme tipi tabii ki direkt adreslemedir. Çünkü bu adresleme tipinde belli bir adres belirtilmemektedir. Saklama sırasında saklanan register'in içeriği değişmediği için (ya da ana işlem ünitesinin içinde hiçbir değişiklik olmadığı için) hiçbir flag etkilenmez. Bilhassa ilk makine dili programları yazarken çok düşülen bu hataya karşı uyaralım dedik: DİKKAT! Sakladığınız değere göre flag-
STA $8000 POKE
$8000
STA $C020,Y POKE YA
$C020
STY $FI
- $OOF1
diğini bir kere daha hatırlatalım. Özetlersek ilk iki bölümde ana işlem ünitesinin en önemli iki komut grubunu gördük. Bu komutlar ana işlem ünitesinin, bilgisayarın hafıza birimleri ile bilgi alış verişini sağlarlar. Bütün programlarda en yoğun kullanılan komut grupları bunlardır.
3. Ana İşlem Ünitesinin İçinde Bilgi Transferi
Şimdiye kadar, ana işlem ünitesinin registerlerinden hafızaya; hafızadan ana işlem ünitesinin registerlerine bilgi transferinin nasıl yapılacağını gördük. Peki ana işlem ünitesinin bir registerinden bir diğerine bilgiyi nasıl göndereceğiz? Bunun için; herhalde, önce hafızaya yazıp sonra hafızadan okumaktan daha kolay bir yöntem olmalı. Evet var, bunlar bir iki basit ve özel komuttan oluşan bir grup. Bu komutlarla, mesela akümülatör'ün içeriğini X-register'ine kopyalayabilirsiniz veya tam tersi... Burada görüldüğü gibi iki registerin belirlenmesi gerekir. Bunlardan birincisi kaynak register'i (bilgi bu register'den çıkacak), diğeri de hedef register'i (bilgi bu register'e ulaşacak) olacaktır. Yapılan işlem ise kaynak register'inin, içeriği bozulmadan, hedef register'inde bir kopyasının oluşturulmasıdır. Bütün transfer komutları bir byte uzunluktadır ve hiçbir operand'a ihtiyaç göstermezler. Yapılacak işlem oldukça açık ve basittir. Bundan başka bu komutlarla yapılan bilgi transferi diğer komutlara göre çok daha hızlı yürür. Şimdi bu komutları tek tek görelim. Tabii bu arada daha anlaşılır olması açısından, aynı işi yapan BASIC'te yazılmış satırlarımızı unutmadık.
TAX
Akümülatör'ün içeriği X-register'ine kopya edilir. Z- ve N-flag'ları etkilenir. Akümülatör'ün içeriği değişmez.
Saklama komutları da yükleme komutları gibi adresleme tiplerine göre 2 veya 3 Byte uzunluğunda olabilirler. Yükleme komutları için belirttiğimiz tüm kurallar aynen geçerlidir. Tabii flag'ların yapılan işlemden etkilenme-
TXA
TAX Bu komut yukarıdakinin tam tersi işlemi yapar. Bilgi akışının yönü değişir. X-register'inin içeriği akümülatör'e kopya edilir. Bu işlem sırasında Z- ve N-flag'ları etkilenir. Burada X-register'inin içeriği etkilenmez.
TAY ği TYA A
Bu komutlar yukarıdakilerin Y-register'ine uygulanmış halidir. Yukarıda belirtilen kurallar aynen geçerlidir. Tek fark, işlemlerin X-register'i yerine Y-register'i ile yapılmasıdır. Geriye kalan iki komut yığın göstergeci (stackpointer) ile ilgili komutlardır. Bu göstergecin ne işe yaradığını tüm detaylarıyla daha ileride göreceğiz. Yığın göstergeci yalnızca X-register'i ile bilgi transferinde bulunabilmektedir.
TSX XxX
Yığın göstergecinin içeriği X-register'ine kopya edilir. Z- ve N-flag'ları etkilenir. Yığın göstergecinin değeri hiçbir şekilde etkilenmez.
TXS SP
Anlaşılacağı üzere, burada yapılan işlem yukarıdakinin tam tersidir. X-register'inin içeriği yığın göstergecine kopya edilir. Bu komut sırasında ana işlem ünitesinin hiçbir flag'ı etkilenmez. Çünkü yığın göstergeci A-, X- ve Y-register'leri gibi işlem register'i değildir. Burada da X-register'inin içeriği korunur. Son iki komut için belirtmemiz gereken bir konu da bunların öyle her yerde değil de, kritik programlarda kullanılan komutlar olduğudur. Aşağıdaki tabloda bu komutları ve onlara ait komut kodlarını bulacaksınız. (Tabii ki burada adresleme tipi diye bir şey söz konusu değil.)
Emir TAX TXA TAY TYA TSX TXS
4. Aritmetik İşlem Komutları
Bu kısımda ana işlem ünitemize hesap yaptıracağız. COMMODORE 64'ümüzün biricik 6510 ana işlem ünitesi direkt olarak sadece toplama ve çıkarmadan anlıyor. Aritmetik işlemler yürütülürken bazı kuralları göz önünde tutmamız gerekiyor. Bunlar: Her hesaplama iki operand'a ihtiyaç gösterir. Sonuç, bu iki operand arasında söz konusu işlem yapıldıktan sonra elde edilir. 6510 ana işlem ünitesinde operand'lardan biri akümülatör'de olmak zorunda. İkinci operand ise hafızada olabilir. Tabii, ikinci operand için değişik adresleme tipleri kullanılabilir. Bulunan sonuç daima akümülatör'de tutulur. Aynı kural bir sonraki kısmımız olan mantıksal işlemler için de geçerli. BASIC komutları ile vereceğimiz örnekler bu anlatılanların daha iyi kavranmasına yardımcı olacaklardır.
İlk önce toplama işlemine göz atalım. Burada hafızanın içeriği akümülatör'e toplanır ve sonuç akümülatör'e yazılır.
ADC
İki adet 8-bitlik sayıyı topladığımızı düşünelim ve sonuç 8-bite sığmayacak kadar büyük olsun (8-biti geçemeyeceği de kesindir, yani yalnızca bir ekstra bite ihtiyacımız olacak). Burada, “elde verme” denilen işlem yapılacaktır. Konuyu lafla değil de örnekle incelersek daha iyi olacak galiba:
ADC #$3A; bu işlemden önce akümülatör $E4 içersin.
$9E — S3A — 9000111010
Toplama işlemi şöyle olacaktır: %10011110 + %00111010
%11011000 = $D8
Burada gördüğünüz ikili sistemdeki toplama işlemi onluk sistemdekinin benzeri kurallarla yürütülmektedir. Göz önünde bulundurmamız gereken durumlar 4 adettir:
Onluk sistemimizde olduğu gibi “elde” olayı, bir sonraki basamakta değerlendirilir. Bu örnekte sonucumuz $D8 veya ikili olarak %11011000 idi. Görüldüğü gibi bu sonuç 8-bite sığdı. Bu olayı bir şans gibi görmektense sığmayacağı durumları da içeren genel bir çözüm görsek daha iyi olacak: ADC #$3A burada akümülatör $E4 içersin. $E4 = %10110100 $3A = %00111010 Toplama işlemi şöyle olacaktır:
Yo 11100100 Yo 00111010
90 100011110
Evet, 8-biti aşmayı becerdik. Ne yapacağız?.. Tabii bizim pek bir şey yapacağımız yok. Ama işlem ünitesinin bu durumda ne yaptığına bakalım. Akümülatör'ümüz 8-biti tutabiliyordu. En alttaki 8 biti o alır. Dokuzuncu bit ise CARRY flag'ine gönderilir. İşte burada CARRY flag'inin esas önemini görmekteyiz. Şayet işlem sonucunda “elde” oluşursa CARRY biti “1” durumuna geçer, şayet “elde” yoksa CARRY biti “0” durumuna geçer. CARRY flag'ını aynı zamanda, toplama işlemlerinde akümülatör'ün dokuzuncu biti olarak görebiliriz. Şayet sekiz bitten daha uzun olan sayıları toplamak istersek CARRY biti imdadımıza yetişir ve sekiz bitlik grupların birbirine bağlanmasını sağlar. Mesela iki adet sekiz bit kullanırsak 0 ile 65535 arasındaki sayıları belirtebiliriz ki bu değer aralığı bile kendi başına birçok problemin çözümünde yeterli olabilir. Bu işlemi yaparken önce alt taraftaki sekiz bitlik kısımları toplarız, daha sonra üst taraftaki sekiz bitlik kısma sıra gelir. Diyelim ki birinci toplama işleminde taşma oldu ve “elde” var. Bu durumda ikinci toplama işlemi sırasında bu “elde”nin değerlendirilmesini sağlamalıyız. İşte burada 6510 ana işlem ünitesinin bir özelliği bizi bu zahmetten kurtarıyor. Çünkü yapılan tüm toplama işlemlerinde CARRY biti de beraber toplanıyor. (Tabii burada ufak bir sorun fark ediyoruz, ilk toplama işlemi sırasında CARRY biti “0” olmak zorunda, yoksa istediğimiz işlemi yanlış yaparız. Bunun için CARRY bitini sıfırlarız. Bununla ilgili komutu daha sonraki bölümlerde göreceğiz.) Şimdi bu toplama işlemini daha doğru olarak bir kere daha yazalım:
ADC SSA ç
$3A Carry biti
Bir toplama işleminden sonra oluşması muhtemel bir aritmetik taşma olayını CARRY flag'ından anlayabiliriz. Toplama işlemi sırasında C-flag'ının yanında N- ve Z- flag'ları da etkilenir. Bunlardan başka V-flag'ı da etkilenir. Bu flag'ın yorumu sadece işaretli aritmetik kullanıldığında (negatif veya pozitif) geçerli olduğundan pek üzerinde durmayacağız. D-flag'ına göre toplama işlemi onluk sisteme benzer şekilde yapılabilmesine rağmen, pek az kullanılan, zahmetli ve tehlikeli bir yöntem olduğu için pek değinmeyeceğiz. Aşağıdaki tabloda ADC komutu için geçerli adresleme tiplerini ve komut kod'larını bulacaksınız.
Adresleme tipi ADC
direkt $69 absolut $6D 0.cı sayfa $65 X-indeksli $7D Y-indeksli $79 0.cı sayfa X-indeks $75 indirekt indeksli indeksli indirekt $61 kat bu sefer yerine “alma” söz konusu. Böyle bir durumda sonuç negatif olacaktır. Gene CARRY flag'ını kullanarak sorunumuzu çözebiliyoruz. “Elde” ve “alma” olayları tümüyle ters şeyleri simgelediklerinden, 'alma' durumunu CARRY flag'ının sönük (0) olması ile belirtiyoruz. Tabii yanık bir CARRY flag'ı “alma” olmadığını gösterecektir. Toplama işlemi için bulduğumuz formül burada da geçerli. Sekiz bitten uzun sayılar arasında çıkarma yaparken, CARRY bitinin yardımını istiyoruz. Şimdi bir örnek ve aynı işi yapan BASIC satırını görelim:
SBC $3A
VA hm $3A Carry biti
İkili sistemde çıkarma işlemi toplama işlemine benziyor. Burada da 4 değişik durum söz konusu:
0-0-0 -1 — | bir sonraki basamaktan *alma” 1-0 =1 1 -1 = 0
Diyelim ki akümülatör'de $7F var. Yukarıdaki işlem şöyle yürür:
$7F $3A
YOL 9000111010
CARRY sönük olarak (yani “alma”
olmadan) yapılan çıkarma işlemi şöyle olacaktır:
Yo 00111010
M01000101 — $45
Sonuç olarak 9001000101, yani $45 elde ettik. Bu sayı pozitif olduğu için herhangi bir “alma” olayı olmayacak ve CARRY biti yanık kalacaktır. Şimdiki örneğimizde akümülatör $1E içersin, CARRY flag'ımız gene yanık:
$1E 9000011110
$3A - 9000111010
Çıkarma işlemi de toplama işlemi ile benzer sınırlar içinde yürür. Hafızanın içeriği akümülatör'den çıkarılır, sonuç toplamada olduğu gibi akümülatör'e yazılır. Burada da toplamadakine benzer bir soruna rastlıyoruz. Fa-
Çıkarma işlemi şöyle gerçekleşecek:
96 00011110 Yo 00111010
%0011100100
Sonuç olarak %0011100100, yani $E4 elde ettik. İşlem sırasında karşılaştığımız için CARRY biti sönecektir. Peki bu olayın yorumunu nasıl yapacağız?.. Konuya daha hakim olmak için onluk sistemde düşünelim. İlk sayımız 30'du, ikincisi ise 58; çıkarma işlemi elde etmemiz lazım. Peki burada bulduğumuz $E4, yani 228 ne alaka?.. Şayet bulduğumuz bu sonucu sekiz bitlik gösterimin sihirli sayısı 256'dan çıkarırsak 28 elde ederiz. Sekiz bitlik gösterimde 255'ten sonra gene 0'a geliriz (256 yerine). İşlemimiz sonucunda CARRY biti sönük olduğu için elde ettiğimiz sonucun negatif olduğunu anlıyoruz. Bu sayının “ikili komplement”ini bularak pozitif karşılığını elde edebiliriz. Bu işlem şöyle yapılıyor: Sayının tüm bitlerini tersine çeviririz ve sonuca bir toplarız:
11100100 bitleri ters çevirirsek: 00011011 artı bir
Sonuç olarak %00011100, yani $1C, yani 28 bulduk.
Aritmetik işlemleri kullanırken dikkat edilmesi gereken şey; toplama işlemlerinden önce CARRY flag'ının söndürülmesi (yanık CARRY flag'ı, olmayan bir elde yaratır ve işlem yanlış yapılır), çıkarma işleminden önce ise CARRY flag'ının yakılmasıdır (sönük bir CARRY flag'ı, olmayan bir alma yaratır ve yanlış sonuç bulunur). (Dijital devre tasarımı ile ilgilenenler için bir not düşelim. Ana işlem ünitesi çıkarma işlemini, toplama işlemini yaptığı devrelerin aynısını kullanarak yapıyor. Tek fark, çıkarma işlemi sırasında çıkarılacak sayının bitlerini ters çevirip toplamak. Geri kalan tüm işlemler olduğu gibi aynı. Mesela CARRY bitinin yorumlanması... İnanmıyorsanız, kâğıt, kalemi elinize alıp birkaç örnek deneyin.) Aşağıdaki tabloda komut kodlarını ve adresleme tiplerini bulacaksınız:
Adresleme tipi SBC
direkt $E9 absolut $ED 0.cı sayfa $E5 X-indeksli $FD Y-indeksli 0.cı sayfa X-indeks $F5 indirekt indeksli $F1 indeksli indirekt $E6