Bu sayfadaki yazılar
Sayfanın metni
Sayfa 28
Selam!!! İşte yine bu ay sizlerle beraberiz ve her zamanki gibi, birlikte Assembler dünyasında biraz uçacağız. Bu arada dergimiz aracılığıyla bana gelen bir mektubu da cevaplamak istiyorum. Bu mektuptaki bazı soruların cevapları gerçekten de eski sayılarda kısaca açıklanmış. Mektubu yazan arkadaşın ismi Tolga ATUĞ. Bu ay size göstermek istediklerim arasında geçen ay da bahsettiğim gibi window kenarlarını bozmadan grafik gösterme var. Diğer değinmek istediğim konular da sürpriz olsun isterseniz. Ehhh, lafı fazla uzatmadan hemen mektubumuza ve ardından da açıklamalarımıza başlayalım...
1. CLR.L Dx ne demek, CLR komutu ne işe yarıyor?
C. CLR komutu, istediğiniz bir register'ın içeriğini silmenize yarar. Bu komutla kullanabileceğiniz register'lar, data register'larıdır. Ayrıca hafızada istediğiniz adresin içeriğini de silebilirsiniz. Komuta eklenebilen '.L', '.W' ve '.B' takılarıyla, silme işleminin o register'daki kaç biti etkileyeceğini belirleyebilirsiniz. Her zamanki gibi '.B' takısı en alt değerlikli 8 biti (bit 0-bit 7), '.W' alt değerlikli 16 biti (bit 0-bit 15) etkiler. '.L' takısı ise register'daki tüm longword'u (32 bit) sıfır konumuna getirir.
2. 8. sayıda yayınlanan örnek programda 2 ve 10, D3 register'ına atanıyor ve (A0)'daki 2 word'de 3 ve 5 oluyor. Yani D3=$00000A02. Peki $A002 ve $0305 nasıl karşılaştırılır?
C. Zannedersem Tolga arkadaşımız programın L1 label'ından sonraki satırları yanlış anlamış. Bu satırlarda yapılan işlemler şunlar: A0 register'ında BUFFER data tablosunun başlangıç adresi bulunmaktadır. 'MOVE.W 2(A0),D3' komutuyla tablodaki 10 değil, 5 rakamı okunur. Nedeni de tablodaki dataların word olarak hazırlanmış oluşudur. 1 word iki byte ettiğine göre, az önceki komutumuz A0 register'ının içeriğindeki adrese 2 ekleyerek tablodaki ikinci sayının adresini elde edecektir. MOVE.W komutuyla sadece bu 5 sayısı D3 register'ına atanır. Programda bir sonraki satırımız olan 'CMP.W (A0), D3' komutu, D3 register'ının içeriğiyle A0 register'ında kayıtlı olan adresin içeriğindeki sayıyı (bu durumda tablodaki ilk rakam 3) birbiriyle karşılaştırır. Bu iki rakamın durumuna göre de gerekli flag'ları açar ya da kapatır. BCC, BEQ, BNE gibi şartlı dallanma komutlarıyla da bu flag'ların konumlarına göre programımızın çeşitli yerlerine dallanabiliriz.
3. DBRA komutu ne işe yarar? C. Bu komut da tıpkı BRA ya da JMP gibi bir direkt dallanma komutudur. Yaptığı işlem ise gayet basit. Verilen Dx register'ını her seferinde bir azaltır. Bu register içeriği -1'den büyük olduğu zamanlarda register'dan sonra verilen label'a gider. Kullanılışı 'DBRA Dx,Label' şeklindedir.
4. TST komutu ne işe yarar? C. Verilen register'ın ya da adresin içeriğini kontrol ederek gerekli flag'ları açar ya da kapatır. Bu flag'lara göre de çeşitli şartlı dallanma komutlarını kullanarak değişik işlemler gerçekleştirebilirsiniz.
5. Bu problem, demin bahsettiğim örnekten ayrı. Mesela '1(A0)' denildiğinde bu ekleme sadece o satır için mi geçerli oluyor, komut uygulanıyor ve alt satırda (A0) tekrar eski halini mi alıyor?
C. Demin de bahsettiğim gibi 1(A0) şeklinde bir adresleme şekliyle A0 register'ının içeriğindeki adrese 1 ekleniyor ve bulunan adresteki data işleme tabi tutuluyor. Bu şekilde bir adreslemeyle A0 register'ının içeriği ya da bu içeriğin gösterdiği adresteki data hiçbir değişmeye uğramıyor. Bu adresleme şekline indeksli adresleme ya da ofsetli adresleme denir.
6. 'MOVEM.L D0-D7/A0-A6,-(A7)'. (A7)'deki - işareti neyi belirtiyor?
C. Dilerseniz bu satırı komple açıklayayım. A7 register'ı hemen hemen her zaman Stack Pointer görevini gerçekleştirmektedir. Stack Pointer kütük göstergeci anlamına gelmektedir ve adından da anlaşılacağı gibi kütüğün bulunduğu adresi gösterir. Kütük nedir? Kütük gerektiği zaman çeşitli sayıları depolamak için kullanabileceğimiz bir depo sayılabilir. Dilediğimiz sayıları buraya atarak saklarız. Daha sonra register içerikleriyle istediğimiz gibi oynayarak çeşitli işlemler yapabiliriz. Yine gerektiğinde de stack'e atılan tüm sayıları tekrar register'larına yerleştirebiliriz. Ayrıca stack bir işe daha yarar. BSR ya da JSR komutu kullanarak dönüşlü bir dallanma yaratmışsak, bu adresten ana programa dönüş adresi stack'in en üstüne atılır. Alt rutinde RTS komutuyla karşılaştığımızda da bu adres geri alınır ve o adre-
se dallanılır. Program satırımızda A7 dışındaki bütün register'ların içerikleri stack'e atılmakta. - (A7) adresleme yöntemiyle stack'in adre- si, buraya her değer atılışında değerin bit uzunluğuna bağlı olarak 1, 2 ya da 4 byte geriye çekilmektedir. Bu sayede stack pointer'ın sayılarımızın başlangıcını gös- termesini sağlayabiliriz. (A7)+ şeklinde bir adreslerle yardımıyla da stack'teki de- ğerleri her alışımızda stack pointer'ın, alı- nan dataların bit uzunlukları kadar ileri alınmasını sağlarız. Bunu ufak bir örnekle daha kolay anlayabiliriz : q: move.l #$fedacb93,d0
move.l #$26711356,d1 move.l a7,a0 movem.l d0-d1,-(a7) move.l a7,a1 movem.l (a7)+,d0-d1 move.l a7,a2 rts Bu örnekte, D0 ve D1 register'ları verdiğimiz sayıyı aynen tutuyor olacaklar. A0, A1 ve A2 register'larında değişik adresler görürüz. A0 register'ında stack pointer'ın ilk baştaki içeriği görülür. Sayıları attıktan sonra stack pointer 8 byte geri çekilmiştir ve A0 register'ının gösterdiği adresin 8 byte (2 longword) öncesini gösterir. A2'de ise yine A0'ın içeriğini görebiliriz. Bu da ikinci MOVEM.L komutundan sonra stack pointer'ın halidir. Şimdi stack pointer'ın gösterdiği adresten sonrasına bir göz atalım. Bunun için Seka'da q komutunu kullanarak A1'deki adresi girin. Bu adresten sonrasının içeriği şu şekildedir: Adres : fe da be 93 26 71 13 56 xx xx XX XX ....
Gördüğünüz gibi adresten sonra gelen ilk longword D0'ın, ikinci longword ise D1'in içeriğini taşımakta, xxxxxxxx ile belirtilen sayı da, hata durumlarında dallanılacak adrestir. Bu adresten sonrasına bir göz attığımızda, burada sadece bir ILLEGAL komutuna rastlıyoruz. Bu komut tüm işlemleri durdurur ve Seka'ya hata mesajı verdirerek dönmemizi sağlar. Bu komutu ilerde daha detaylı göreceğiz.
Programlarınızda A7 yerine SP'yi de kullanabilirsiniz. SP, stack pointer kelimelerinin başlangıç harfleridir. Bu sayede programlarınızı daha anlaşılır yapabilirsiniz. Seka, programınızı assemble ederken SP gördüğü yerleri A7'ye otomatik olarak dönüştürür.
7. Bir sorum da register'lardaki ilk byte veya word ile ilgili. Yani 'CMP.W $50000,D0' komutunda, D0=$1efd5432. Burada $50000 adresindeki ilk sayı ($1efd) $50002'deki sayı ($5432) ile mi karşılaştırılacak?
C. Bir register her zaman 32 bittir (1 longword=2 word=4 byte). Eğer bunun en alt byte'ını (bit 0-bit 7) kullanmak istersek, bunu komuttan sonraki takıyla gerçekleştirebiliriz. Bu takıyı '.B' yapmamız gerekmekte. Aynı şekilde en alt iki byte için (alt word) '.W' takısını kullanmamız
AMIGA ASSEMBLER
Klavyeyle gezinmek için ← ve → tuşları.
Sayfa 29
gerekmekte.
Direkt adreslemede bu değişmekte. Şayet bir adresteki değeri '.B' takısını kullanarak etkilersek, o adresteki byte değişir. '.W' takısı o adresteki ve adresten sonraki byte'ı değiştirir. '.L' takısı da o adreste yer alan longword'u etkileyeceğinden, adresten sonraki 4 byte birden komutumuza göre değişir. Aşağıda bu konuyla ilgili basit örnekler yer almakta: CLR.L D0 ==> D0 içeriğini komple temizler. MOVE.W D5,D3 ==> D5'in alt word'unu (bit 0-bit 15)
D3'e kopyalar. MOVE.W $50000,D2 ==> $50000'de yer alan word'u (ilk iki byte) D2'ye kopyalar. MOVE.L $42000,A0 ==> $42000'de yer alan longword'u
A0'a kopyalar. 8. Örnek 10.1'de 'MOVE.L D0,INTBASE' komutu var, sonra 'BEQ EXIT3' komutu var ama CMP komutu yok, o zaman karşılaştırma nasıl olacak?
C. Birçok komut işlem yaparken aynı zamanda flag'leri de etkiler. Bu yüzden bu tür bir komut kullandığınızda ekstradan bir CMP komutu daha kullanmanız gerekmez. Flag'leri etkileyen komutlardan bazıları: MOVE, AND, ADD, ASL, BSET, BCLR, BTST, CMP, DIVU, EOR, LSR, MULU, NEG, NOT, OR, ROL, RTE, RTR, SUB, SWAP, TAS, TST.
9. Son örneklerde 'BEQ.L' görülüyor, longword olması ne işe yarar? Bir de mesela 'BEQ.S' deniyor. '.S' neyi ifade ediyor?
C. Bu takılar arasında ufak bir fark var. 512 byte'lık sınırlar içinde yakın bir label'a dallanmak istediğinizde, bunu ister BEQ.S, isterseniz de BEQ.L komutuyla yapabilirsiniz. BEQ.S komutunu kullandığınızda assemble edilmiş programda bir word tasarruf edersiniz. BEQ.S komutu ve ardından gelen label hafızada bir word yer kaplar. Oysa BEQ.L kullandığınızda, bu 2 word olmakta. Gördüğünüz gibi pek fazla bir şey fark etmiyor. Dilerseniz Seka'da assemble ederken 'O' opsiyonunu kullanarak Seka'nın tüm bu takıları yerleştirmesini sağlayabilirsiniz. Bu takılar tüm dallanma komutları için geçerli.
10. 'MOVE.L 4A6' gibi durumlarda adresin atanacağı register fark eder mi?
C. Hayır. A6 register'ının kullanılış nedeni, herkesin bu register'ı kullanmasıdır. Dilerseniz A0'ı da kullanabilirsiniz. Ama bu durumda JSR -$nnn(A6) komutlarını da değiştirmeniz gerekmekte. Şimdiye kadar hiçbir programda farklı bir adres register'ının kullanıldığını görmedim. Ama bu kullanılmaz anlamına gelmez.
11. 'JMP -$228(A6)' neden (A6) ile toplama gereği duyuluyor, direkt adres yazılsa olmaz mı? Yoksa format mı öyle?
C. Bunun sebebi library adreslerinin hafızada düzenlenişi ile ilgilidir. Bütün Amiga'larda yazılan programların hatasız çalışabilmesi için sistemi hazırlayan programcılar biraz dolaylı bir yöntem kullanmışlar. Fakat bu dolaylı yöntemin en büyük avantajı, yeni bir KickStart versiyonu çıktığında sorun olmadan her programın çalışabilmesidir. Bu nasıl gerçekleşmekte? Bunu anlamak için library'lerin hafızadaki durumlarına kısaca bir göz atalım.
Bütün çok kullanılan library'ler hafızada sabit olarak bulunmaktadırlar. Library fonksiyonlarının yerleştiği adresler, $fc0000 ve yukarısıdır. Tabii bu, yeni Amiga'lar olan A-3000 ve A-3500'lerde değişmekte. Fakat şu an herkesin normal Amiga'lardan (KickStart v1.2 ya da v1.3) kullandığını farz edelim. Bir library'i açtığımızda aslında yapılan işlem bir tablonun RAM'e kopyalanmasıdır. Bu tablo aslında bir dallanma tablosudur. Burada o library'nin bütün fonksiyonlarının gerçek adreslerine dallanan JMP komutları görülmekte. KickStart versiyonun değiştiğini kabul edelim. ROM'daki bazı rutinler değişmiş olacak. Bazıları uzamış, bazıları da kısalmış olacak. Bu durumda bütün library fonksiyonlarının adresleri değişecek. Eski bir Amiga'da direkt adresler kullanılarak yazılan bir program, tümüyle hatalı çalışacaktır. Fakat sistemi yaratanlar, dallanma tablosu kullanarak sadece tablodaki adresleri değiştirmekle tüm uyumsuzluğu ortadan kaldırmışlar. Library'lerden herhangi birini açtığımızda, bu library'nin başlangıç adresi bize D0 register'ı sayesinde aktarılıyor. Base adresten sonraki değerler o library'e ait bazı önemli datalardır. Biz bu dataların tümüne BASE STRUCTURE adını veriyoruz (ExecBase Structure gibi). Base adresinden ÖNCE ise, tüm dallanma tablomuz yer almakta. Bu dallanma tablosuna da erişmek istiyorsak, -nnn(a6) adresleme şeklini kullanmalıyız. Tabii aynı şekilde şöyle de yazabilirdik:
move.I 4,a6 sub.l #$-228,(a6) jmp (a6)
Fakat bu, hem programımızı boşu boşuna uzatacak, hem de her seferinde a6 register'ının içeriğini bozacaktır.
12. BSR komutunun görevi nedir? C. BSR ve JSR komutları dönüşlü dallanmayı sağlarlar. Bunun anlamı şudur: İlk önce komutun yer aldığı satırın altındaki satırın adresini stack'e atar. Sonra komuttan sonra verilen label'a ya da adres'e dallanır. Oradaki tüm işlemleri gerçekleştirdikten sonra, RTS (ReTurn from Subroutine) komutuna rastladığında stack'teki adresi alır ve o adrese zıplar. Altrutinlerden RTS yerine yine bir dallanma komutu kullanırsak, dönüş adreslerinin her seferinde stack'e atıldığını unutmayın. Altrutinden RTS yerine JMP ya da BRA gibi bir komutla ana rutine dönerseniz, stack'teki adres silinmeyecektir. Ana programınızın sonunda da RTS komutuna rastladığında stack'teki adrese dallanmak isteyecektir. Bu da hata yaratacak, belki de bilgisayarınızı crash ettirecektir.
13. 'MOVE.L D0,WINBASE'deki window durum bilgileri nedir?
C. Library açtığımızda D0 register'ında bu library'nin base adresi yer alır. Bu base adresinden sonra gelen tüm datalar o library hakkında önemli bilgiler taşıyan LIBBASE STRUCTURE'una aittir. Daha ilerde bu structure'ları detaylı olarak inceleyeceğiz. Biz şimdilik library base adresini, o library'e ait fonksiyonlara erişmek için kullanıyoruz. Library base adresinden önce gelen dallanma tablosu sayesinde library fonksiyonlarına erişebiliriz.
14. 'DC' yani data satırı ile kullanılan '.L', '.W' ve '.B' takıları neyi değiştirir? Önemli olan onu oradan nasıl aldığımız değil mi?
C. Data satırlarında 'DC' komutundan sonra kullanılan takı ile sayıların takıya göre aynı bit uzunluklarında olmaları sağlanmakta. Eğer bir 'DC.W' satırı kullanırsak ve MOVE.L ile buradan bir sayı almaya kalkarsak, alınan sayı iki word olacaktır. Oysa data satırlarında DC.L kullandığımızda sayımızı doğru olarak okuyabiliriz. Aynı şekilde data satırlarında DC.L kullanıp MOVE.B ile ilk sayıyı okuduğumuzda, genelde 0 elde ederiz. DC.L ile her sayıya 4 byte rezerve edilmekte ve sayımız 256'dan küçükse (byte sınırını aşmıyorsa) longword'umuzdaki ilk üç byte değişmemektedir. Eğer sayı word sınırını aşmıyorsa, bu sefer longword'daki ilk iki byte 0 değerini alacaktır.
Umarım Tolga arkadaşımızın tüm sorularını anlayabileceği bir şekilde cevapladım. Bu sorular sayesinde bazı bilinmeyenlere de ışık tutmaya çalıştım. Fakat hala kafanızı kurcalayan sorunlarınız olduğunda bana yazmaktan çekinmeyin. Ehh, artık bu ayki bölüme ne yazık yer kalmadı. Bu yüzden bu ay sadece programımızı yayınlayacağım. Programın açıklamasını da artık gelecek ay göreceğiz. Ayrıca programı açıkladıktan sonra gelecek ay tüm assembler komutlarının listesini ve kullanılışlarını vereceğim.
************************************************************** ** AMIGA DÜNYASI AMIGA ASSEMBLER KURSU ** ** INTUITION LIBRARY - WINDOW EXAMPLE ** ** ORNEK 19.1 ** ************************************************* START: movem.l d0-d7/a0-a6,-(sp) bsr.s IMTLIBS bsr.L IMTSCREEN