(C)2012 LGB Gábor Lénárt LenartG@invitel.co.hu A project celja: nemi C alapu fejlesztes lehetove tetele az Enterprise-ra. Erre eszkoz lehet az sdcc nevu (open source) C fordito, ami kepes Z80-ra forditani. Azonban nincs neki architektura specifikus resze, amivel a kod betoltheto lenne EP-re. A feladat tehat a "crt0" resz megirasa. Mivel az sdcc sajat assembleret kell erre hasznalni, egyutt kell tudni elni a nemikepp fura szintaxissal peldaul (szokasos -> sdcc as): ld a,2 -> ld a,#2 ld a,(ix+2) -> ld a,2(ix) Lathatoan az assemblere nem tamogatja a macrokat sem. Ugyan az sdcc dox szerint ez mar valtozott, amde az altalam hasznalt verzional meg nem volt, ujat forditani meg meg nem probaltam, jelenleg altalam hasznalt verzio: 2.9.0 (sdcc), 01.75 (as). A crt0.s file tartalmazza a kerdeses kodreszletet, a legfontosabb dolgok: * EXOS 5-os fejlec prezentalasa * stack pointer beallitasa (nem 0x100-ra, ugyanis C programban nagyobb stack igeny varhato: a STACK_SIZE-t lehet allitani, azzal egyutt a program "fole" helyezi a stack-et a STACK_SIZE-al megallapitott mertekben) * GSINIT. Sajnos az sdcc-nek van egy fura tulajdonsaga: az initializalt globalis C valtozokra _KODOT GENERAL_ az inicializalashoz, ahelyett hogy letarolna siman mint const (konstans) globalisok eseten. Ennek oka az lehet, hogy az sdcc project elegge MCU specifikus (AVR, PIC) ahol a kod es adat teljesen kulonvallik (Harvard architecutra) igy ott nem lehet letarolni elore adatot. Bar ez Z80-nal total felesleges, en nem talaltam meg a modjat, hogy sdcc-re maskepp csinalja. Addig is az lehet a jo eljaras, hogy ne nagyon hasznaljunk inicializalt globalis valtozokat, ha ilyen kene elonyosebb const-kent tarolni, akkor nem kell az inicializalo kod. * EXOS csatornak megnyitasa VIDEO:, KEYBOARD: es SOUND: tekinteteben. A VIDEO:-nal persze kell elokeszulet is (EXOS valtozok beallitasa, lasd a crt0.s elejen, azokat az ertekeket hasznalja), illetve a csatorna megnyitasa utan a 11-es EXOS hivas 1-es alfunkciojaval a megjelenites maga. * a main() hivasa, asm szinten a C szimbolumok underscore-ral kezdodnek, tehat a _main kell nekunk. Mivel a main() visszateresere szamitunk, --main-return opcioval kell a C-s reszeket forditani! * Az sdcc - mint ahogy a C forditok altalaban - a stack-en taroljak a fuggvenyek parametereit hivaskor (is esetleg valtozokat is). Mivel a Z80 nem rendelkezik SP relativ cimzessel, erre a celra az sdcc az IX regisztert hasznalja, amit minden fuggvenynek sajat magnak kell mentenie, illetve az "SP-hez igazitania" hogy kvazi SP helyett lehesen hasznalni. Ha egy fuggveny visszateresi erteke byte-nyi, akkor az az L regiszterben van. Ez az ismeret kell ahhoz, hogy assembly-ben tudjunk C-bol hivhato fuggvenyt irni (ha csak reszben kell - pl inline assembler C-ben - akkor az IX mentese es visszatoltese es sp-hez igazitasa a ret-tel egyutt persze elmaradhat, felteve ha nem "naked"-kent van a fuggveny deklaralva). * Ahhoz, hogy C-ben altalanos input/output menjen (stdio), kell platform specifikus resz. Az sdcc ezt eleg kenyelmesen csinlja: csupan ket fuggvenyt var el, hogy az ember megirjon, aztan minden tudja azt hasznalni. Ezek a putchar() es getchar() fuggvenyeket. Ezeket szinten a crt0.s-ben implementalom, a megfelelo VIDEO: illetve KEYBOARD: irassal/olvasassal EXOS funkciokon at. * Ha a main() visszatert, kovetelmeny lehet, hogy szegeny user lassa mi van a kepernyon azert ... Ezert kiirunk egy szoveget, majd varunk egy billentyulenyomasra, ezek utan a BASIC kapja meg a vezerlest. Az sdcc rosszabb kodot eredmenyez signed valtozok eseten, ha lehet, mindig hasznaljunk unsigned-et! A char-ra nezve (8 bites) az ansi C szerint signed kell, ezert alapbol az sdcc is ezt teszi. Ugyan kerhetjuk az sdcc-t, hogy legyen default unsigned a char, amde akkor elojon egy bug, amit allitolag amugy ujabb verziokban mar javitottak: http://sourceforge.net/tracker/index.php?func=detail&aid=2798646&group_id=599&atid=100599 A generalt program merete viszonylag nagy lesz. Ennek oka az, hogy pl a printf hasznalata eseten hozzalinkelodik a programhoz a kerdeses kodreszlet, aminek komplexitasa eleg magas szinten all, atlag 3K folott lesz egy abszolut minimal program ekkor mar, es float tamogatas meg igy nincs is benne. Limitaciok/TODO: * ha 16K-ba nem fer bele a program (pontosabban 16K-BSS-STACK_SIZE-0x100) az valoszinuleg fagyni fog. Vagy szegmens foglalast kene implementalni amit belapoz maganak aztan, vagy pedig a programot ki kell egesziteni a linkeles utan utolag annyira, hogy abba beleferjen az egesz (futasi allapotot nezve a memoriahasznalatra!) es ehhez persze modositani aztan a fejlecet is. * Az SDCC limitacioi: altalaban a fuggvenyek nem re-entrant modban vannak forditva, stb. * Az SDCC-re jellemzo - mar emlitett - inicializalt nem konstans globalis valtozok kerdese: vagy ravenni (patch-elni?) az sdcc-t hogy ezt ne tegye, vagy vmi utolagos feldolgozo script-tel kivagni az asm-ra forditott programbol es utana az as-z80-al forditani, bar ez nemileg csunya/komplex megoldas lenne. A forditas menete (Linuxot feltetelezve, nem elek MS drogokkal): Installalni kell az sdcc es a binutils (lasd lentebb) csomagokat. Ha nincs ilyen alapbol a disztribucioban installalhato formaban (az sdcc, a binutils-nak kene lennie minden Linuxon kb), akkor persze mas forrasbol beszerezni: http://sdcc.sourceforge.net/ Ezek utan: sdcc -mz80 --main-return --opt-code-size -c prg1.c sdcc -mz80 --main-return --opt-code-size -c prg2.c sdcc -mz80 --main-return --opt-code-size -c prg3.c as-z80 -o crt0.o crt0.s sdcc -mz80 --no-std-crt0 --code-loc 0xF0 --data-loc 0 -o linkage crt0.o prg1.o prg2.o prg3.o objcopy -I ihex -O binary linkage.ihx result A pelda feltetelezi, hogy a project itt harom darab C forrasfile-bol all (prg1.c, prg2.c, prg3.c). Nyilvan lehet tobb, vagy akar egy is, mas nevvel is. Nyilvan erdemes lehet egy Makefile-t is osszeutni az adott project-re! Az sdcc ujabb hivasa (az as-z80 utan) a linkelesi fazis. Eloszor is nem kerjuk az std crt-t, ezt jelezzuk a --no-std-crt0 kapcsoloval. Aztan 0xF0-ra kerjuk a kod szegmenst, ennek oka az, hogy 16 byte az EXOS fejlec, tehat a valodi kod 0x100 cimre kerul a memoriaban majd. A --data-loc beallitja az adatszegmenst, amennyire ertem, 0-t adva automatice a kod utan teszi, ez kell nekunk. Az eredmeny a linkage.* file-okba kerul. Utana az sdcc object file-ok felsorolasa jon, az elso kotelezoen a crt0.s object-je, utana johet a tobbi amit az elejen C-bol forditottunk. Ha mindez megvolt, sdcc szeeeeep intel hex format nevu cumot allit elo, ami igy nem jo semmire. Az objcopy-t (altalaban Linux-okon a binutils csomagban van, azt kell installalni hozza) hasznalja, hogy "nyers" binarissa konvertaljuk. Az eredmeny a "result" nevu file lesz, ami - elvileg - EP-n ekkor mar betoltheto gond nelkul. Megjegyzesek ujabb (>2.9) sdcc kapcsan: Sajnos a helyzet nem lett jobb. Eloszor is ossze-vissza valtoztatjak a kulonbozo verziok kozott a hasznalt neveket, eddig object.o volt, kesobb mar object.rel mukodik csak a linkernek bemenetkent ... Masodszor, az inicializalt valtozok kezelese meg katasztrofikusabb, kvazi nem mukodik. Raadasul KETSZER tarolja le oket valamiert, es a gsinit sem vegzi a dolgat valahogy :( Az altalam ismert egyetlan workaround hogy egyaltalan ne hasznaljunk inicializalt valtozokat! Vagy legyenek const tipusuak. Ha kell inicializalni es nem lehet const, akkor tegyuk meg kodbol, azaz pl: int a = 1; helyett: int a; a = 1; Raadasul ujabb sdcc eseten a crt0 is modositando, mert uj szegmensek jelentek meg. A generalt kod merete is nagyobb :( Azt tudom mondani, hogy a 2.9-es verzio sokkal hasznalhatobb, es javareszt mukodik is. Egyetlen hatranyat latom (a mar emlitett gsinit stb mellett): a mar emlitett unsigned char by default eseten elhasal a fordito ... Sajnos az mondhato, hogy az sdcc nem egy tul normalis fordito, teljesen MCU specifikus, ossze van mosva benne a linker/fordito dolga, a linker nem konfigolhato kvazi (ellentetkeppen lasd a 6502-re fordito cc65 linkeret ahol sajat config file hozhato letre szinte tetszoleges lehetosegekkel stb) ami igen megneheziti az ember dolgat, ha barmi speckot akar, foleg, ha olyanrol van szo, amire az sdcc-t eredetileg nem terveztek (sdcc prioritasa az MCU, illetve, hogy nem RAM-ban van a program, hanem ROM-ban, ezert nem is modosithato a program altal; ezek miatt van hogy pl a valtozok inicializalasa ennyire korulmenyes es nem hatekony).