CC65

From Atariki

Revision as of 09:21, 8 kwi 2008; view current revision
←Older revision | Newer revision→
Jump to: navigation, search

Właściwie The 6502C compiler. Pakiet kompilatora języka C, asemblera (CA65), librariana, oraz linkera. Pierwotnie napisany przez Johna R. Dunninga na małe Atari. Obecnie rozwijana wersja potrafi kompilować pod różne mikrokomputery oparte o procesor 6502, jak i 65816 (np. różne odmiany Atari 8-bit, Commodore C64/C128/C16/C116 i inne, Apple II, Nintendo NES...), ale tylko jako tzw. cross-compiler - z komputerów udostępniających większe zasoby pamięci, mocniejsze procesory.

Poniżej znajduje się nieco kulawy wstęp (w głównej mierze autorstwa Tebego) do używania tego cross-kompilatora na PC, spod dowolnego systemu postdosowego.

Spis treści

Wstęp do instrukcji

Kod źródłowy piszemy na PC w dowolnym edytorze tekstu, jak Notatnik czy CodeGenie itp.

Pliki do pobrania

Cały pakiet programów do tworzenia w C znajdziemy na stronie domowej projektu, patrz Linki.

Możemy też od razu wpaść na ftp-a i pobrać plik z bibliotekami dla Atari XE/XL cc65-atari-WERSJA.zip oraz plik z kompilatorem przeznaczonym dla konkretnej platformy OS/2, Dos, Windows, np. cc65-win32-WERSJA.zip czyli Windows, bądź, dla platform unixowych, plik ze źródłami (cc65-sources-WERSJA.tar.bz2), kompilowalnymi z użyciem standardowych autotools.

Instalacja

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ć trochę zmiennych środowiskowych, aby kompilator, linker wiedział gdzie co jest. W przypadku rodziny Windows 9x, dopisujemy w pliku AUTOEXEC.BAT:

PATH=%PATH%;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, bądź przelogowujemy się i możemy zacząć bawić się CC65 pod Windowsem. (Zamiast ustawiać te zmienne na stałe, można również utworzyć plik wsadowy (.bat) uruchamiany z wiersza poleceń i ustawiający je tylko dla danej sesji tegoż wiersza poleceń)

Składniki pakietu

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
          wyświetli nam listę modułów wchodzących w skład biblioteki atari.lib

   ca65 - makro assembler dla procesorów 6502, 65C02 i 65816

   cc65 - kompilator języka C przeznaczony dla rodziny procesorów 6502

   cl65 - program narzędziowy służący jako nakładka na kompilator i linker w jednym

   co65 - programik do konwersji skompilowanych plików obiektowych do postaci źródeł assemblerowych

   od65 - object dumper - pokazuje zawartość plików obiektowych (symbole, eksporty, importy, segmenty)

   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 plik wykonywalny

Przykład 1

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;
}

Kompilacja

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 optymalniejszy 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

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;
}

Programik 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 :)

Przykład 3

Przykład 3:

/* 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"

Uwagi

Nie ma jednak róży bez kolców. Wstawianie wstawek assemblerowych musi odbywać się poprzez pliki z rozszerzeniem *.s, bądź mało czytelne wywołanie ASM("kod"). Przydzielana 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.

CA65

Asembler dodawany do pakietu CC65.

Linki

Personal tools