CC65

From Atariki

Revision as of 17:12, 12 gru 2004; view current revision
←Older revision | Newer revision→
Jump to: navigation, search

Sam program piszemy na PC w dowolnym edytorze tekstu jak Notatnik czy CodeGenie itp, a kompilator C czyli cc65 zamieni nam go na kod maszynowy 6502. Cały pakiet programów do tworzenia w C znajdziemy na stronie domowej projektu CC65

Możemy też od razu wpaść na ftp-a ftp.musoftware.de/pub/uz/cc65/ i pobrać plik z bibliotekami dla Atari XE/XL cc65-atari-2.10.0-1.zip oraz plik z kompilatorem przeznaczonym dla konkretnej platformy OS/2, Linux, Windows, np. cc65-win32-2.10.0a-1.zip czyli Windows.

Jeśli mamy już ściągnięte oba pliki, znajdujemy dla nich miejsce na którejś z partycji (np. C) i rozpakowujemy je do np. katalogu C:\CC65

Teraz musimy jeszcze ustawić troche zmiennych środowiskowych, aby kompilator, linker wiedział gdzie co jest. W przypadku rodziny Windows 9x, dopisujemy w pliku AUTOEXEC.BAT:

PATH=tutaj cos juz jest;C:\CC65\BIN

SET CC65_INC=C:\CC65\INCLUDE
SET CC65_LIB=C:\CC65\LIB
SET LD65_CFG=C:\CC65\DOC

W przypadku Windows 2000, XP, robimy to następująco:


Mój Komputer -> Właściwości -> Zaawansowane -> Zmienne środowiskowe -> dopisujemy w oknie Zmienne systemowe, czyli klikamy "Nowa" i uzupełniamy oba pola "Nazwa zmiennej" i "Wartość zmiennej" podobnie jak ma to miejsce w AUTOEXEC-u.


Teraz resetujemy komputer i możemy zacząć bawić się CC65 pod Windowsem.


W katalogu C:\CC65\BIN znajdują się wszystkie pliki wykonywalne pakietu cc65:

    ar65 - program do tworzenia bibliotek *.lib i operacji na nich, np. ar65 l atari.lib
           wyswietli nam listę modułów wchodzących w skład bibioteki atari.lib

    ca65 - makro assembler dla procesorów 6502, 65C02 i 65816
    
    cc65 - kompilator języka C przeznaczony dla rodziny procesorów 6502
    
    cl65 - kompilator i linker w jednym
    
    co65 - programik do operacji na skompilowanych plikach *.o
    od65 - też coś robi z plikami *.o
    
    da65 - disassemler, stosuje zapis strawny na makro assemblera ca65
    
    grc  - to się Atarowcom nie przyda, bo jest to kompilator dla systemu GEOS z C64
    
    ld65 - linker, czyli programik który składa do kupy wszystko i tworzy atarowskiego exe-ka

Teraz wypadałoby coś skompilować, czas więc na nieśmiertelny przykład, pewnie w Basic'u też to pisaliście.

Przykład 1:

#include < stdio.h >

int main (void)
{
 printf("Hello, world!\n");
 return 0;
}

Nasz program zapiszemy do pliku np. "hello.c", aby go skompilować piszemy "cl65 -O -t atari hello.c -o hello.xex" i to wszystko, powstał plik HELLO.XEX który możemy już wczytać spod DOS-a. Uruchomienie go bezpośrednio nic nie da, musi być uruchomiony spod DOS-a.

Parametry które przekazaliśmy kompilatorowi cl65 oznaczają (wielkość liter jest rozróżniana):

    -O        optymalizacja kodu, tworzy szybszy kod maszynowy
    -t sys    docelowy system, domyślnie jest to C64 :P
    -o plik   nazwa pliku wyjściowego

Wywołanie cl65 to najszybszy i najprostszy sposób kompilacji. Skompilowany program domyślnie ładuje się od $2E00, startuje od $2E01, maksymalna długość skompilowanego programu może wynieść $8E20 bajtów. Stos programowy liczy $0800 bajtów pamięci. Strona zerowa używana jest od bajtu $82-$FF.


Domyślne ustawienia dla linkera (plik ATARI.CFG):

MEMORY {
    ZP: start = $82, size = $7E, type = rw, define = yes;
    HEADER: start = $0000, size = $6, file = %O;
    RAM: start = $2E00, size = $8E20, file = %O;    # $8E1F: matches upper bound $BC1F
}
SEGMENTS {
    EXEHDR: load = HEADER, type = wprot;
    CODE: load = RAM, type = wprot, define = yes;
    RODATA: load = RAM, type = wprot;
    DATA: load = RAM, type = rw;
    BSS: load = RAM, type = bss, define = yes;
    ZEROPAGE: load = ZP, type = zp;
    AUTOSTRT: load = RAM, type = wprot;
}
FEATURES {
    CONDES: segment = RODATA,
	    type = constructor,
	    label = __CONSTRUCTOR_TABLE__,
	    count = __CONSTRUCTOR_COUNT__;
    CONDES: segment = RODATA,
	    type = destructor,
	    label = __DESTRUCTOR_TABLE__,
	    count = __DESTRUCTOR_COUNT__;
}
SYMBOLS {
    __STACKSIZE__ = $800;	# 2K stack
}

Jednak jakiekolwiek zmiany w pliku *.CFG nie zostaną zauważone jeśli będziemy kompilować używając komendy "-t atari", trzeba ją zastąpić przez "-C atari.cfg". Jeśli chcemy mieć też wpływ na typ CPU dla którego będzie generowany kod, lepiej jeśli rozbijemy proces generowania pliku wyjściowego na kompilację, asemblację i linkowanie, wtedy wszystko będzie pod kontrolą.

    cc65 -O --cpu 6502 -t atari hello.c -o hello.s
    ca65 -t atari hello.s -o hello.o
    ld65 -C atari.cfg -o hello.xex atari.o hello.o atari.lib

Kompilator cc65 tworzy z pliku hello.c plik hello.s, następnie makro assembler ca65 z pliku hello.s tworzy hello.o i ostatecznie linker ld65 z pliku hello.o i przy pomocy biblioteki atari.lib i atari.o oraz pliku konfiguracyjnego atari.cfg tworzy wykonywalny plik Atari hello.xex

Jeśli chcemy aby kod programu był wykonywany na 65816, zmieniamy zapis --cpu 6502 na --cpu 65816. Czyż nie jest to cudownie proste :).

Przykład 2:

#include < stdio.h >

int main (void)
{
 char str1[30],str2[30];
 int i;
 
 puts("wprowadz lancuch 1"),gets(str1);
 puts("wprowadz lancuch 2"),gets(str2);

 for (i=0; str1[i]==str2[i]; i++)
 {
 }
 
  if (str1[i]==0)       // standard ansi, ciag znakow zakonczony zerem
  {
   puts("oba lancuchy sa identyczne");
   return 0;
  }

   puts("lancuchy sa rozne");
 
 return 0;
}

Progamik pyta się o dwa łańcuchy znaków, potem je porównuje i informuje czy łańcuchy są identyczne, czy też różne. Jest jeszcze biblioteczna funkcja C -> "strcmp" która porówna ciągi, ale przecież jej użycie byłoby zbyt proste :)

<b><u>Przykład 3:</u></b>
<pre>
/* clock example: countdown */
#include < stdio.h >
#include < time.h >

void wait ( int seconds )
{
  clock_t endwait;
  endwait = clock () + seconds * CLK_TCK ;
  while (clock() < endwait) {}
}

int main ()
{
  int n;
  printf ("Starting countdown...\n");
  for (n=10; n>0; n--)
  {
    printf ("%d\n",n);
    wait (1);
  }
  printf ("FIRE!!!\n");
  return 0;
}

Programik zlicza od 10 do 0, wypisując stosowny komunikat na ekranie. Jest to też przykład wykonania opóźnienie z użyciem "time.h"


Nie ma jednak róży bez kolców. Wstawianie wstawek assemblerowych musi odbywać się poprzez pliki z rozszerzeniem *.s, a tak zwiększona liczba plików nie sprzyja ogólnej czytelności projektu. Przydzialana programowi pamięć w zasadzie mieści się w granicy $2000-$BFFF, troche mało jeśli ktoś myśli o większym projekcie. Problem z pamięcią miał też autor atarowskiej wersji systemu Contiki, który posłużył się specjalnie okrojoną wersją DOS - PicoDos aby tylko wcisnąć więcej kodu poniżej adresu $2000.

Personal tools