CC65
From Atariki
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 kompilacja - 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 z platformy PC, spod dowolnego systemu postdosowego.
Spis treści |
Wstęp do instrukcji
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.
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
Ten artykuł to tylko zalążek. Możesz pomóc rozwojowi Atariki poprzez rozszerzenie go o więcej informacji.