CC65
From Atariki
Wersja z dnia 00:31, 8 wrz 2005 KMK (Dyskusja | wkład) ← Previous diff |
Wersja z dnia 19:24, 13 paź 2005 Jellonek (Dyskusja | wkład) Next diff → |
||
Linia 1: | Linia 1: | ||
'''The 6502 C compiler''' | '''The 6502 C compiler''' | ||
+ | |||
+ | [[CC65]] jest pakietem kompilatora języka [[C]], [[Assembler|assemblera]] ([[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ózne 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 [[Tebe]]-go) do używania | ||
+ | tego cross kompilatora z platformy PC, spod dowolnego systemu postdosowego. | ||
+ | |||
+ | |||
+ | ---- | ||
+ | |||
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. | 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. | ||
Linia 5: | Linia 17: | ||
[http://www.cc65.org CC65] | [http://www.cc65.org CC65] | ||
- | + | Możemy też od razu wpaść na ftp-a [ftp://ftp.musoftware.de/pub/uz/cc65/ ftp.musoftware.de/pub/uz/cc65/] 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, | |
- | Możemy też od razu wpaść na ftp-a [ftp://ftp.musoftware.de/pub/uz/cc65/ 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. | + | plik ze źródłami ('''cc65-sources-''WERSJA''.tar.bz2'''), kompilowalnymi z użyciem standardowych |
- | + | autotools. | |
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 | 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 | ||
Linia 13: | Linia 25: | ||
Teraz musimy jeszcze ustawić troche zmiennych środowiskowych, aby kompilator, linker wiedział gdzie co jest. W przypadku rodziny Windows 9x, dopisujemy w pliku AUTOEXEC.BAT: | 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=%PATH%;C:\CC65\BIN | |
- | <pre> | + | |
- | PATH=%PATH%;C:\CC65\BIN | + | SET CC65_INC=C:\CC65\INCLUDE |
- | + | SET CC65_LIB=C:\CC65\LIB | |
- | SET CC65_INC=C:\CC65\INCLUDE | + | SET LD65_CFG=C:\CC65\DOC |
- | SET CC65_LIB=C:\CC65\LIB | + | |
- | SET LD65_CFG=C:\CC65\DOC | + | |
- | </pre> | + | |
W przypadku Windows 2000, XP, robimy to następująco: | W przypadku Windows 2000, XP, robimy to następująco: | ||
- | <br /> | + | <tt>Mój Komputer -> Właściwości -> Zaawansowane -> Zmienne środowiskowe -></tt> dopisujemy w oknie <tt>Zmienne systemowe</tt>, czyli klikamy <tt>"Nowa"</tt> i uzupełniamy oba pola <tt>"Nazwa zmiennej"</tt> i <tt>"Wartość zmiennej"</tt> podobnie jak ma to miejsce w AUTOEXEC-u. |
- | <tt> | + | |
- | Mój Komputer -> Właściwości -> Zaawansowane -> Zmienne środowiskowe -></tt> dopisujemy w oknie <tt>Zmienne systemowe</tt>, czyli klikamy <tt>"Nowa"</tt> i uzupełniamy oba pola <tt>"Nazwa zmiennej"</tt> i <tt>"Wartość zmiennej"</tt> podobnie jak ma to miejsce w AUTOEXEC-u. | + | |
- | <br /> | + | Teraz resetujemy komputer, bądź przelogowujemy się i możemy zacząć bawić się CC65 pod Windowsem. |
- | Teraz resetujemy komputer 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ń) | ||
- | <br /> | ||
W katalogu C:\CC65\BIN znajdują się wszystkie pliki wykonywalne pakietu cc65: | W katalogu C:\CC65\BIN znajdują się wszystkie pliki wykonywalne pakietu cc65: | ||
- | <pre> | ||
ar65 - program do tworzenia bibliotek *.lib i operacji na nich, np. ar65 l atari.lib | 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 | wyswietli nam listę modułów wchodzących w skład bibioteki atari.lib | ||
- | + | ||
ca65 - makro assembler dla procesorów 6502, 65C02 i 65816 | ca65 - makro assembler dla procesorów 6502, 65C02 i 65816 | ||
- | + | ||
cc65 - kompilator języka C przeznaczony dla rodziny procesorów 6502 | cc65 - kompilator języka C przeznaczony dla rodziny procesorów 6502 | ||
- | + | ||
- | cl65 - kompilator i linker w jednym | + | cl65 - program nażędziowy służący jako nakładka na kompilator i linker w jednym |
- | + | ||
co65 - programik do konwersji skompilowanych plikaów objektowych do postaci źródeł assemblerowych | co65 - programik do konwersji skompilowanych plikaów objektowych do postaci źródeł assemblerowych | ||
+ | |||
od65 - object dumper - pokazuje zawartość plików obiektowych (symbole, eksporty, importy, segmenty) | od65 - object dumper - pokazuje zawartość plików obiektowych (symbole, eksporty, importy, segmenty) | ||
- | + | ||
da65 - disassemler, stosuje zapis strawny na makro assemblera ca65 | da65 - disassemler, stosuje zapis strawny na makro assemblera ca65 | ||
- | + | ||
grc - to się Atarowcom nie przyda, bo jest to kompilator dla systemu GEOS z C64 | 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 | + | ld65 - linker, czyli programik który składa do kupy wszystko i tworzy plik wykonywalny |
- | </pre> | + | |
Teraz wypadałoby coś skompilować, czas więc na nieśmiertelny przykład, pewnie w BASIC-u też to pisaliście. | Teraz wypadałoby coś skompilować, czas więc na nieśmiertelny przykład, pewnie w BASIC-u też to pisaliście. | ||
- | <b><u>Przykład 1:</u></b> | + | '''<u>Przykład 1:</u>''' |
- | <pre> | + | #include < stdio.h > |
- | #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. | ||
- | int main (void) | ||
- | { | ||
- | printf("Hello, world!\n"); | ||
- | return 0; | ||
- | } | ||
- | </pre> | ||
- | Nasz program zapiszemy do pliku np. "hello.c", aby go skompilować piszemy "<b>cl65 -O -t atari hello.c -o hello.xex</b>" 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. | ||
- | <br /> | ||
- | <br /> | ||
Parametry które przekazaliśmy kompilatorowi cl65 oznaczają (wielkość liter jest rozróżniana): | Parametry które przekazaliśmy kompilatorowi cl65 oznaczają (wielkość liter jest rozróżniana): | ||
- | <pre> | ||
-O optymalizacja kodu, tworzy optymalniejszy kod maszynowy | -O optymalizacja kodu, tworzy optymalniejszy kod maszynowy | ||
-t sys docelowy system, domyślnie jest to C64 :P | -t sys docelowy system, domyślnie jest to C64 :P | ||
-o plik nazwa pliku wyjściowego | -o plik nazwa pliku wyjściowego | ||
- | </pre> | ||
- | Wywołanie <b>cl65</b> to najszybszy i najprostszy sposób kompilacji. Skompilowany program domyślnie ładuje się od <b>$2E00</b>, startuje od <b>$2E01</b>, maksymalna długość skompilowanego programu może wynieść <b>$8E20</b> bajtów. Stos programowy liczy <b>$0800</b> bajtów pamięci. Strona zerowa używana jest od bajtu <b>$82-$FF</b>. | ||
- | <br /> | ||
- | <br /> | ||
+ | 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): | Domyślne ustawienia dla linkera (plik ATARI.CFG): | ||
- | <pre> | + | MEMORY { |
- | MEMORY { | + | ZP: start = $82, size = $7E, type = rw, define = yes; |
- | ZP: start = $82, size = $7E, type = rw, define = yes; | + | HEADER: start = $0000, size = $6, file = %O; |
- | HEADER: start = $0000, size = $6, file = %O; | + | RAM: start = $2E00, size = $8E20, file = %O; # $8E1F: matches upper bound $BC1F |
- | RAM: start = $2E00, size = $8E20, file = %O; # $8E1F: matches upper bound $BC1F | + | } |
- | } | + | SEGMENTS { |
- | SEGMENTS { | + | EXEHDR: load = HEADER, type = wprot; |
- | EXEHDR: load = HEADER, type = wprot; | + | CODE: load = RAM, type = wprot, define = yes; |
- | CODE: load = RAM, type = wprot, define = yes; | + | RODATA: load = RAM, type = wprot; |
- | RODATA: load = RAM, type = wprot; | + | DATA: load = RAM, type = rw; |
- | DATA: load = RAM, type = rw; | + | BSS: load = RAM, type = bss, define = yes; |
- | BSS: load = RAM, type = bss, define = yes; | + | ZEROPAGE: load = ZP, type = zp; |
- | ZEROPAGE: load = ZP, type = zp; | + | AUTOSTRT: load = RAM, type = wprot; |
- | AUTOSTRT: load = RAM, type = wprot; | + | } |
- | } | + | FEATURES { |
- | FEATURES { | + | CONDES: segment = RODATA, |
- | CONDES: segment = RODATA, | + | type = constructor, |
- | type = constructor, | + | label = __CONSTRUCTOR_TABLE__, |
- | label = __CONSTRUCTOR_TABLE__, | + | count = __CONSTRUCTOR_COUNT__; |
- | count = __CONSTRUCTOR_COUNT__; | + | CONDES: segment = RODATA, |
- | CONDES: segment = RODATA, | + | type = destructor, |
- | type = destructor, | + | label = __DESTRUCTOR_TABLE__, |
- | label = __DESTRUCTOR_TABLE__, | + | count = __DESTRUCTOR_COUNT__; |
- | count = __DESTRUCTOR_COUNT__; | + | } |
- | } | + | SYMBOLS { |
- | SYMBOLS { | + | __STACKSIZE__ = $800; # 2K stack |
- | __STACKSIZE__ = $800; # 2K stack | + | } |
- | } | + | |
- | </pre> | + | |
- | Jednak jakiekolwiek zmiany w pliku <b>*.CFG</b> nie zostaną zauważone jeśli | + | Jednak jakiekolwiek zmiany w pliku '''*.CFG''' nie zostaną zauważone jeśli |
- | będziemy kompilować używając komendy <b>"-t atari"</b>, trzeba ją zastąpić przez <b>"-C atari.cfg"</b>. 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ą. | + | 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ą. |
- | <pre> | ||
cc65 -O --cpu 6502 -t atari hello.c -o hello.s | cc65 -O --cpu 6502 -t atari hello.c -o hello.s | ||
ca65 -t atari hello.s -o hello.o | ca65 -t atari hello.s -o hello.o | ||
ld65 -C atari.cfg -o hello.xex atari.o hello.o atari.lib | ld65 -C atari.cfg -o hello.xex atari.o hello.o atari.lib | ||
- | </pre> | ||
- | Kompilator <b>cc65</b> tworzy z pliku <b>hello.c</b> plik <b>hello.s</b>, | + | Kompilator '''cc65''' tworzy z pliku '''hello.c''' plik '''hello.s''', |
- | następnie makro assembler <b>ca65</b> z pliku <b>hello.s</b> tworzy <b>hello.o</b> i ostatecznie linker <b>ld65</b> z pliku <b>hello.o</b> i przy pomocy biblioteki <b>atari.lib</b> i <b>atari.o</b> oraz pliku konfiguracyjnego <b>atari.cfg</b> tworzy wykonywalny plik Atari <b>hello.xex</b> | + | następnie makro assembler '''ca65</b> 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 | Jeśli chcemy aby kod programu był wykonywany na 65816, zmieniamy zapis | ||
- | <b>--cpu 6502</b> na <b>--cpu 65816</b>. Czyż nie jest to cudownie proste :). | + | '''--cpu 6502''' na '''--cpu 65816'''. Czyż nie jest to cudownie proste :). |
- | <b><u>Przykład 2:</u></b> | + | '''<u>Przykład 2:</u>''' |
- | <pre> | + | #include < stdio.h > |
- | #include < stdio.h > | + | |
- | + | ||
- | int main (void) | + | |
- | { | + | |
- | char str1[30],str2[30]; | + | |
- | int i; | + | |
- | puts("wprowadz lancuch 1"),gets(str1); | + | int main (void) |
- | puts("wprowadz lancuch 2"),gets(str2); | + | |
- | + | ||
- | for (i=0; str1[i]==str2[i]; i++) | + | |
{ | { | ||
- | } | + | 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 | if (str1[i]==0) // standard ansi, ciag znakow zakonczony zerem | ||
Linia 147: | Linia 142: | ||
return 0; | return 0; | ||
} | } | ||
- | + | ||
puts("lancuchy sa rozne"); | puts("lancuchy sa rozne"); | ||
- | return 0; | + | 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 :) | 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> | + | '''<u>Przykład 3:</u>''' |
- | <pre> | + | /* clock example: countdown */ |
- | /* clock example: countdown */ | + | #include < stdio.h > |
- | #include < stdio.h > | + | #include < time.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; | ||
+ | } | ||
- | 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; | ||
- | } | ||
- | </pre> | ||
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" | 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, bądź mało czytelne wywołanie ASM("kod"). 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. | |
- | 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. | + | |
- | + | ||
{{stub}} | {{stub}} |
Wersja z dnia 19:24, 13 paź 2005
The 6502 C compiler
CC65 jest pakietem kompilatora języka C, assemblera (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ózne 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 Tebe-go) do używania tego cross kompilatora z platformy PC, spod dowolnego systemu postdosowego.
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-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.
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=%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ń)
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 - program nażędziowy służący jako nakładka na kompilator i linker w jednym co65 - programik do konwersji skompilowanych plikaów objektowych 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
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 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</b> 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 :)
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"
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"). 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.
Ten artykuł to tylko zalążek. Możesz pomóc rozwojowi Atariki poprzez rozszerzenie go o więcej informacji.