Amiga C

27. Bölüm

Cenker Özkurt

C dili bütün hızıyla devam ediyor. Artık hepinizin Amiga C diline ısınmış olduğunu farzediyorum. Bu nedenle daha profesyonel çalışmalara girebileceğimizi tahmin ederekten, bu ayki konumuzu geçen aylarda vermiş olduğum C'de Assembler dilinin kullanımının biraz daha gelişmişi olarak seçtim.

Önceki sayılarda C'den Assembler alt rutinlerinin nasıl kullanıldığını ve hazırlandığını öğrenmiştik. Bu ay, C'den Assembler alt rutinlerine nasıl parametre yollandığını daha derinlemesine inceleyeceğiz. Bunu yapmak için ilk olarak isterseniz bir C ve C'den çevrilme Assembler rutinini inceleyelim:

main()
{ 
rutine1(1,2,3,4);
rutine2(10,20,30,40); 
rutine3(4,3,2,1);
}
Üç adet rutinin çağrıldığı basit bir C programı görüyorsunuz. Rutinler içerisinde dikkat ettiyseniz parametreleri de mevcut. Rutinlerin işlevlerini gözönüne almıyoruz. Şimdi bir de bu programın assembler'a çevrilmiş halini inceleyelim:
;:ts=8 
;main()
;{
    public  _main 
_main:
    link  a5,#.2
    movem.l.3,-(sp) 
;rutine1(1,2,3,4);
    pea 4
    pea 3
    pea 2
    pea 1
    jsr  _rutine1
    lea 16(sp),sp 
;rutine2(10,20,30,40);
    pea 40
    pea 30 
    pea 20
    pea 10
    jsr _rutine2
    lea 16(sp),sp 
;rutine3(4,3,2,1);
    pea 1
    pea 2
    pea 3
    pea 4
    jsr _rutine3  
    lea 16(sp),sp
;}
.4
    movem.l(sp)+,.3
    unlk a5
    rts
.2  equ 0
.3  reg
    public  _rutine3
    public  _rutine2
    public  _rutine1
    public  .begin
    dseg
    end
Assembler listesi yukarıdaki C programına ait. Şimdi dikkat edilecek nokta, alt rutinlerin nasıl kullanıldığı ve parametrelerin yollanması. C programından takip ederseniz, birinci rutinde 1, 2, 3 ve 4 sayıları parametre olarak yollanmış. Assembler listesinde ise bu parametrelerin SP (Stack Pointer) gösteregecine aktarılarak yollandığını görüyoruz. Buradan da anlaşılıyor ki, parametreler SP'a yerleştiriliyor. Bu durumda bizim yapmamız gereken, rutin içerisinde iken parametreleri SP'den geri almak. Aşağıdaki örnek programı dikkatle izleyin:
int a;

main()
{ 
a=topla(0,5,10,20);
printf("a= %d",a); 
}

#asm 
_topla:
    move.l  4(sp),d0
    add.l 8(sp),d0
    add.l 12(sp),d0
    add.l 16(sp),d0
    rts

    public  _topla 
#endasm
Program içerisinde bir toplama rutini hazırladım. Bu rutin verilen dört adet sayıyı toplayarak geri dönüyor. İlk olarak topla() rutinini çağırıyoruz:
a=topla(0,5,10,20);
Yollanan parametreler 0, 5, 10 ve 20 sayıları olsun. Bu parametreler ilk örnekteki gibi SP'ye aktarılacaktır. Daha sonra program Assembler alt rutinine sıçrayarak parametreleri SP'dan alacaktır. Bu iş için SP'nin gösterdiği adresin 4 ilerisinden ilk parametreyi alıyoruz. Çünkü SP'ye son yollanan değerden sonra, SP, 4 byte azaltılır. SP, yollanan her değerden sonra 4 azaltıldığından, diğer parametreleri de 4'er aralıkla SP'den çekiyoruz:
move.l  4(sp),d0   ; 1. parametre   
add.l	8(sp),d0   ; 2. parametre
add.l	12(sp),d0  ; 3. parametre
add.l	16(sp),d0  ; 4. parametre 
Değerler toplanarak D0 register'ına yükleniyor. RTS assembler komutu ile de, C'ye geri dönüyoruz. Toplam değer D0 üzerinde olduğundan sonuç 'a' değişkenine aktarılıyor ve 'printf()' ile değerin doğruluğunu kontrol ediyoruz. Evet parametre yollamanın püf noktalarını öğrendiğinize göre artık daha kapsamlı bir örneğe geçebiliriz.

Aşağıda vermiş olduğum program, Assembler yardımıyla library'yi ve ekran açmamızı sağlıyor. Fakat bu ekranın bazı özellikleri mevcut. İlk olarak 'show_bitmap();' rutini ile istediğiniz hafıza bölgesini C'den kontrol ederek gösterebiliyorsunuz. İsterseniz programımıza bir göz atalım:

/* Programming by C. OZKURT */ 
/*  (c) 1992 Amiga Dünyası  */ 
#include <exec/memory.h> 
#include <graphics/gfxbase.h> 
#include <intuition/intuitionbase.h>

struct GfxBase *GfxBase; 
struct RastPort rp; 
struct BitMap bm;

main()
{
start();	      /* library ve ekranı aç */
set_color(1,0xfff);   /* birinci rengin paletini 0xfff yap */ 
Move(&rp,0,0); 
Draw(&rp,320,256);    /* sistem komutları ile çizgi çiz */
left_mouse();         /* sol mouse kontrolu */
stop();		      /* library ve ekranı kapa */
}

alloc_start()
{
InitBitMap(&bm,3,320,256);
bm.Planes[0]=AllocMem(10240,MEM _CHIP|MEMF_CLEAR);
bm.Planes[1]=AllocMem(10240,MEM _CHIP|MEMF_CLEAR);
bm.Planes[2]=AllocMem(10240,MEM _CHIP|MEMF_CLEAR);
InitRastPort(&rp);
rp.BitMap=&bm;
}

alloc_stop()
{
FreeMem(bm.Planes[0],10240); 
FreeMem(bm.Planes[1],10240); 
FreeMem(bm.PlanesI2],10240);
}

start()
{
lib_start(); 
alloc_start();
/* Acmis olduğumuz 3 bitplane'lik hafiza bolgesini goster */ 
/* show_bitmap(plane1, plane2, plane3); */

show_bitmap(bm.Planes[0],bm.Planes[1],bm.Planes[2]);
scr_start();
}

stop()
{ 
scr_stop();
alloc_stop();
lib_stop();
}

#asm

_left_mouse:
    btst    #6,$bfe001
    bne.s   _left_mouse
    rts

_lib_start:
    move.l  4,a6
    lea	    Gfxname,a1
    jsr	    -408(a6)
d0=openlibrary(a1)
    move.l  d0,_GfxBase
    jsr	    -132(a6); forbid();
    rts

_lib_stop:
    move.l   4,a6
    move.l   _GfxBase,a1
    jsr      -414(a6); closelibrary(a1)
    jsr      -138(a6); permit()
    rts

_scr_start:
    lea		copper,a0
    move.l	_GfxBase,a6
    move.w	#$00a0,$dff096 
    move.l	50(a6),oldcop
    move.l	a0,50(a6)
    move.w	#$8380,$dff096
    rts

_scr_stop:
    move.l	_GfxBase,a6
    move.w	#$00a0,$dff096
    move.l	oldcop,50(a6)
    move.w	#$83a0,$dff096
    rts

show_bitmap:   move.l #bitmap,a0
    move.w	4(sp),2(a0)
    move.w	6(sp),6(a0)
    move.w	8{sp),10(a0)
    move.w	10(sp),14(a0)
    move.w	12(sp),18(a0)
    move.w	14(sp),22(a0)
    rts
_set_color:
    move.l	#color+2,a0
    move.l 	4(sp),d0
    mulu	#4,d0
    move.l 	8(sp),d1 
    add.l       d0,a0 
    move.w 	d1,(a0)
    rts
    
    dseg
copper:
    dc.w   $0100,$3200,$0102,$0000
    dc.w   $0108,$0000,$010a,$0000
    dc.w   $0092,$0038,$0094,$00d0
    dc.w   $008e,$3081,$0090,$30c1
bitmap:
    dc.w   $00e0,$0000,$00e2,$0000
    dc.w   $00e4,$0000,$00e6,$0000 
    dc.w   $00e8,$0000,$00ea,$0000
color:
    dc.w   $0180,$0000,$0182,$0f00
    dc.w   $0184,$000f,$0186,$00f0
    dc.w   $0188,$0ff0,$018a,$00ff
    dc.w   $018c,$0c0c,$018e,$0aff
    dc.w   $ffff,$fffe

Gfxname:   dc.b 'graphics.library',0
otdcop:    dc.l 0
    cseg
    public  _set_color
    public  _left_mouse
    public  _show_bitmap
    
; #endasm
Program temel olarak 3 bitplane'lik bir bitmap yaratıyor. Bu bölgeyi AllocMem() sistem fonksiyonu ile ayırıyoruz. İkinci kademede bu bölgeyi daha önce açmış olduğumuz 'copper' ekranı ile gösteriyoruz. İlk olarak library'ler aşağıda olduğu gibi bir assembler rutini (lib_start();) ile hazır hale getiriliyor.

Bu rutinde 'graphics.library' açılıyor. Kapama işlemini ise lib_stop() assembler rutini ile gerçekleştiriyoruz.

_lib_start:
    move.l  4,a6
    lea  Gfxname,a1
    jsr  -408(a6) ; d0=openlibrary(a1)
    move.l  d0,_GfxBase
    jsr  -132(a6); forbid(); 
    rts

_lib_stop:
    move.l  4,a6 
    move.l  _GfxBase,a1
    jsr  -414(a6); closelibrary(a1)
    jsr  -138(a6);permit()
    rts
Copper ekranımız aşağıdaki rutinlerde hazırlanıyor:
_scr_start:
    lea  copper,a0
    move.l  _GfxBase,a6
    move.w  #$00a0,$dff096 
    move.l  50(a6),oldcop
    move.l  a0,50(a6)
    move.w  #$8380,Sdff096
    rts

_scr_stop:
    move.l  _GfxBase,a6
    move.w  #$00a0,$dff096
    move.l  oldcop,50(a6)
    move.w  #$83a0,$dff096
    rts
scr_start() ekran açma, scr_stop() kapama rutinimiz. Copper listemiz ise listenin sonunda bulunuyor. Bu listeyi kontrol ederek renk ve göstermesi gereken hafıza bölgesini seçebiliyoruz. set_color() rutini istediğimiz rengin paletiyle oynamamızı sağlıyor, show_bitmap() ise harika bir rutin, istediğimiz hafıza bölgesini gösteriyor. Biz burada açmış olduğumuz bitmap bölgesini seçiyoruz. Yapmış olduğumuz işlemleri rahatça test edebilmek için.

Şimdi gelelim programımızın compile işlemlerine. Programda dikkat edilecek husus, copper listesinin CHIP hafızada bulunmasıdır. Aksi takdirde program çalışmaz. Çünkü bildiğiniz gibi Amiga'nın DMA (Direct Memory Access) entegresi yalnızca CHIP hafızaya ulaşabiliyor ve diğer işlemcilere bilgi yollayabiliyor. Eğer FAST hafızanız yoksa problem yok. Sonuç olarak program hep CHIP'te çalışacaktır. Fakat FAST'li bir alete geçtiğinizde programın FAST'te çalışma olasılığı oldukça fazla. Bu durumda programınız çalışmaz. Programın devamlı CHlP hafızada çalışmasını sağlamak için link sırasında +C (CHIP) opsiyonunu koymalıyız. Bu opsiyon ile program her zaman için CHIP hafızaya yüklenecektir. Örnek göstermek gerekirse;

CC +L prog.c
LN +C prog.o -lc32
işlemlerini yapmalıyız. Artık programı yazıp seyretmek size kalmış. Bu aylık da benden bu kadar. Gelecek ay hızlı rutinlerle buluşmak üzere, saygılar....