Az Amiga Gépi gódú programozása Dee Jay álatal írt leírás fordítása Tartalomjegyzék --------------- 1. Bevezetés 1.1 Mi a fene az a gépi gód 1.2 Kukucskáljunk bele az amiga memóriáiba 1.2.1 RAM,ROM,harver regiszter 1.2.2 Bitek,byte-ok és szavak 1.2.3 Számrendszerek 1.3 Az amiga felépítése (boncolda) 1.3.1 Összetevők és könyvtárak 1.3.2 A memória 1.3.3 Multi-task 1. FEJEZET ---------- 1. Bevezetés ------------ Mielőtt belecsapnánk a gépi gódú programozásba egy pár alavető dolgot meg kell ismerni. 1.1. Mi a fene az a gépi kód ---------------------------- A gépi gód alatt ebben az esetben a MC68000-es processzor által értelmezhető nyelv. Minden más nyelvnél mint pl. BASIC, Pascal, C, előszőr gépi kódra fordul. (parancsértelmező vagy lefordított kód). Ez a fordítás történhet futás közben (Basic interpreter), vagy a program futása előtt (Pascal és C fordítók) Előnyök: A gépi kódban írt programok sokkal gyorsabbak mit egy interpreteres vagy egy fordító által készített kódnál. Az interpreteres nyelveknél mint pl. a BASIC minden sor egyenként lefordul, majd ezután végrehajtódik, ami egy nagyon időigényes feladat. A Pascal és C fordítók a forrást gépi kóddá fordítja, ezután lehet őket futtatni. A fordítási folyamat általánosítása miatt azonban ez a módszer sem eredményez olyan gyors programokat mintha tisztán gépi kódban írták volna meg. A másik nagy előnye a gépi kódnak, hogy nincs szükség bonyolult értelmezőkre és fordítókra. A gépi kód a gép minden képességét ki tudja aknázni. Ez lehjetővé teszi, hogy a gép subrutinjait közvetlenül hívja elkerülve a magasbb programozási nyelvei által használt funkcióhívásokat. 1.2 Kukucskáljunk bele az amiga memóriáiba ------------------------------------------ Mielőtt elkezdenénk bőszen programozni, meg kell ismerni, mire van szükség egy program működéséhez. Tudnunk kell, milyen erőforrások állnak rendelkezésre, és azokat miként tudjuk elérni. A legfontosabb erőforrások az amigában a memóriában rejlenek. 1.2.1. RAM,ROM,Hardware regiszterek ----------------------------------- Random Access Memory (Véletlen elérésű memória) arra utal, hogy a RAM-ba (memóriába) adatokat rakhatunk bele, amiket később előhívhatunk onnan. Ez a memória olyan elektonikai elemekből épül fel, ami csak addíg tartja meg az adatokat, amíg a számítógép be van kapcsolva (vagy nem lesz áramszünet). Ahhoz, hogy a számítógép a bekapcsolás után képes legyen egy ábrát megjeleníteni pl. a workbench disk behelyezését kérni, egy olyan memóriában lévő programra is szükség van, ami áram nélkül is megtartja az információkat. Ez a második memória tipus a ROM. ROM: A ROM a Read Only Memory (csak olvasható memória rövidítése).Ebből a memóriából mint a neve is mutatja, csak olvaasni lehet, ebbe adatokat visszaírni fizikailag lehetetlen. Az amigában lévő ROM a workbench vagy a kickstart beolvasását kísérli meg a hátértárakról (vgy mutatja azt a kék lemezt h nem találja az elérhető háttértarakon). Az elsó tipusú amigáknál a kikstart is lemezen volt. PROM: A ROM egy variációját nevezik PROM-nak, azaz Programmable Read Only Memory-nak. Ez a ROM egy olyan fjtája, amit egyszer fel lehet programozni. Ez többet nem törölhető, és elég ritkán használják. Az elterjedtem verziója az EPROM, ami Erasable Programmable ROM, azaz könnyen programozható ROM-ot jelent. Ez egy speciális chip, amit az ultraibolya fénnyel törölni lehet egy kis átlátszó ablakon keresztül, ami a chip tetején található. (Ne vidd szoláriumozni) EEROM: A fogyasztói piacszámára elég ritkán kapható, és meglehetósen borsos áru az Electrically Erasble ROM (elektromosan törölhető ROM lehetne a RAM alternatívája, ha nem lenne olyan drága. Ez a chip úgy működik mint a RAM, de tartalmát nem veszíti ela tápfeszültség megszűntekor. (Jegyzem meg ez ma már töegcikk pl. pendrive akár több gigabytos kapacitással, de akkoriban egy R10-es számítógép mellett dolgoztam, amiben ferritgyűrűs megoldással alkottak ilyen RAM- ot, a kütyü több 10 milka volt, és egy kétajtós szekrény volt a mérete, lyokszalaggal meg lyukkártyával ment, erről külön lehetne mesélni, de a lényeg tényleg az volt, hogy este menet közben lenyomtad a főkapcsolót, reggel meg a reggelesek felnyomták, és folytatta munkát ott ahol abbahagyta. Nagyon poén volt) WOM: Az amiga születésének egyik terméke lett a WOM. Ez a különleges memória tipus a Write Once Memory (Egyszer írt Memória). A régi amigákban ebbe töltődött be a kickstart az első indításkor. Ezek után ebbe a memóriába többet nem íródott semmi, csak olvasni lehetett. Ez akkoriban, egy teljesen új találmány volt, egy egyszerű RAM, amit a betöltés után csak olvasásra zároltak, ezek után abból ugye értelem szerűen csk olvasni lehetett. Regiszterek: A ROM és a RAM melett van még egy memória típus. Ez a memóra köti össze a processzort a külső perifériákkal. Eeket éppen ezért Hardware Regiszetreknek nevezik, és ezeken keresztül vezérlik a rendszert. Azt hogy ezeket a regisztereket hogyan kell használni, a későbbiekben fojuk tárgyalni ezen könyv lapjain (ide esetleg majd egy oldaszámot kéne böfögni, ha már kész lesz a doksi) Most nézzük meg hogy épül fel a memória, és hogyan tudjuk használni. 1.2.2. Bit-ek, Byte-ok, Szavak. ------------------------------- Bit: A információ alapegysége. Értéke lehet 0, vagy 1. (nincs áram a cellában, van áram a cellában) Byte: Egy byte 8 egymás meletti bitből áll, azaz 2^8-on értéket vehet fel ami 0-tól 255-ig terjedhet (256 különböző értket tartlmazhat). Az 512 kbyte ami az amiga(500)-ban van az 2^19=524288byte azaz 4194304 bit. Ez így látszara elég elképzelhetetlen szám, de léneg hogy a memória a 2^4194300 különböző kombinációját tárolhatja. Kilobyte: (hogy miért ezzel kezdik az relytély majd megfordítjuk a sorrendet) A memória méretét Kilobyte-ban mérik(Kbyte) (Ma már persze Mb vagy Gb) Egy kilobyte 1024 byte-ot tartalmaz, nem 1000 ahogy elvárhatnánk. Ez a számítógép azon tulajdonságából adódik, hogy az binárisan a 2-es számrendszer többszöröseivel dolgozik. 10 byte-on 2^10-en azaz 1024 kombináció állítható elő, innen jön ki ez az eltérés. (aztán még hablatyol itt valamit ai teljesen zagyva) Szavak: A bitek és byte-ok teljesen elegendőek eg olyan processzornál ami 8 bites pl. a 6500, hiszen ez egyszerre csak egy byte-al tud dolgozni (na jó kezdem unni ez innentől időnként bájt lesz). A programozáshoz a 16/32 bites processzoroknál mint amilyen az amiga MC68000-es processzora, két új adattipusra van szükség, ez a 16 bites szó(word)(egyenlő 2 byte) és a 32 bites hoszú szó (long word)(egyenlő 4 bájtal azaz 2 szóval). A szó 0 és 65535 közötti számot tartalmazhat, a hosszú szó 0 és 4294967295 szám lehet. Az MC68000 processzor ezekkel a gigantikus számokkal egy művelettel tud boldogulni. Időnként szükség van negatív számok használatára is. A bit csak 0 és 1 értéket vehet fel, nem lehet értéke -1, ezért egy alernatív megoldást találtak ki. Ha a szó tartalmaz egy speciális jelet, a legmagasabb számjegye vagy máskénnen fogalmazva a 15.bitje a szónak (a pozició mindíg a 0-ás bittől számolódik), akkor az előjeles számnak tekinthető. Ezzel a módszerrel a szavak -32768-tól +32768-ig tartalmazhatnak számokat. Ez egy byte-nál -127-től +127-ig lehet. Bájtokban a -1 $FF, szavakban bedig $FFFF, a -2 pedig $FE, illetve szavaknál $FFFE, stb. A pozitív számokkal fogjuk vizuálisan is megértetni a bitek elhelyezkedését et bitmezőben. A gépi kód nem igazán tud dolgozni a 10-es számrendszerrel. A kettes 8-as (oktális) és 16-os (hexadecimal) számrendszert ismeri. 1.2.3. Számrendszerek --------------------- Vegyük a 10-es számrendszer. Ennek alapja a 10 es szám. Minden szám a 10 hatványával leírható. A 246 a következő képpen írható le: 2*10^2 + 4*10^1 + 6*10^0. A 10-es számrendszerben tíz szám áll rendelkezésünkre egy hatványon belül ezek 0-9.ig terjednek. Bináris: A bináris számrendszerben csak két különböző szám van a 0 és az 1. Ezekkel a számokkal az 1010 a következő decimális értéket adja: 1*2^3(8) + 0*2^2 + 1*2^1(2) + + 0*2^0 azaz 10 A bináris számokat legegyszerűbb egy egyszerű táblázattal meghatározni. Mennyi az 110010 decimálisan. A válasz 50 és a legegyszerűbb módszer erre összeadni a számokat az alábbi táblázat alapján helyiérték: 8 7 6 5 4 3 2 1 Decimási ért:128 64 32 16 8 4 2 1 azaz 32+16+2=50 Oktális: Az oktális rendszer is hasonló a fentiekhez, ennek alapja azonban a 8. A számkészlete 0 és 7 közötti számokat tartalmaz. A 10-es számrendszerben lévő 31 oktális megfelelője a:1*8^1 + 1*8^0=25. Az oktális számrendszer nem nagyon használt a programozásban. A 16-os számrendszer 0-tól F-ig terjedő 16 karakterkészletet használ. A decimális 15 az hexa F. A $ előjel jelzi, hogy a mögötte lévő szám hexadecimális. A bináris és hexadecimális számrendszerek a legfontosabbak az assembly programozók számára. Hex; Egy hexadecimális byte ábrázolása, ami 0-255-ig terjedhet mindíg két számjegyen történik:$00-$FF-ig. Egy szó tartomány $0000-$ffff-ig míg egy hosszú szó $00000000-$ffffffff-ig terjed. Bináris számokat hexa számokká konvertálni rendkívül egyszerű. Egyszerűen négyes csoportokra kell osztani a bináris számokat, majd ezekből már könnyen előállítható a hexa szám. Íme egy példa: bináris szám:%110011101111 bontva: %1100 %1110 %1111 eredmény: $C $E $F azaz: %110011101111=$CEF Fordítsuk meg a műveletet hexa $E30D bontva :$e $3 $0 $D eredmény %1110 %0011 %0000 %1101 azaz: $E30D = %1110001100001101 Ez a módszer oktális számrendszereknél is alkalmazható oda vissza, csak itt 3 jegyű bináris számokra kell bontani a számokat: oktális szám 7531 bontva 7 5 3 1 eredmény %111 %100 %011 %001 azaz: octal 7531=%111101011001 Az így kapott bináris értéket átkonvertáljuk hexadecimálisra: bináris zsám %111101011001 bontva %1111 %0101 %1001 eredmény $F $5 $9 azaz: octal 7531=$F59 A következő példában ezt a számot konvertáljuk decimálissá: hexadecimal $F59 bontva $F $5 $9 eredmény 15*16^2+5*16+9 azaz: $F59=3929 decimal Bár ezek az átalakítások elég egyszerűek , nagyon macerás tud lenni sokszor megcsinálni. Sok assembler fordító megkönnyíti a dolgodat az által, hogy egy ?- el jelölt számit vissza tud adni decimális és hexadecimális alakban is.Ezek rendelkeznek olyan számológépekkel amik a számkonverziókat végre tudják hajtani. Minden olyan karakter, szám grafikus elem ami a számítókéb felé érkezik átalakítódik bináris számokká, akárcsak a szavak és a hosszúszavak is. Ez a folyamat fordítva is megtörténik. Ha a számítógép meg akar jeleníteni egy adatot a képernyőn, akkor ezeket a bináris számokat karakterekké kell konvertálnia. A későbbi fejezetekben a gépi kódú programozásnál ezekre a folyamatokra példákat fogunk mutatni, melyeket fel tudsz használni a saját kódodban is. Mielőtt belcsapnánk a lecsóba, még pár dolgot meg kell ismerni az amiga gépi kódú programozásához. 1.3. Az amiga felépítése (boncolda) ---------------------------------- Ahhoz hogy az Amigát programozzuk nem elegendő csak a processzor gépi kódú utasításait ismerni, ismerni kell magát a környezetet, az Amigát is. Kukkantsuk hát bele az amigába. 1.3.1. Összetevők és könyvtárak. ------------------------------- Az Amiga egy nagyon összetett gép, mivel olyan dolgok is vannak beleépítve, amik a munka jelentős részét el tudják végezni a 68000-es prosűcesszor helyett. Ezeket custom chipeknek nevezik, melyek különféle feladatokat látnak el a 68000- es processzortól függetlenül. Custom chipek; Ezeket a feladatokat 3 chip végzi, amiket valami nőbolod tervező Agnus-nak, Denice-nek, és Paula-nak nevezett el. Az Agnus (normálisabb nevén blitter) fő feladata nagy memóriadarabok mozgatása, amivel segíteni tud a képernyőn gyors változásokat végezni. A Denise a felelős azért, hogy képernyőre kerüljenek az adatok. A Paula feladata az input/Output (Bemenet/Kimenet) kezelése, beleértve a lemezműveleteket (in/out) és a hangot (általában out) A három chiphez a processzor különbőző címeken fér hozzá amik a $DFF000-on kezdődnek, és hardver regiszternek nevezik. (Ezekről bővebb információkat a a megfelő fejezetekben fogjuk ismertetni). Ahhoz hogy ezeket a chipeket kihasználjuk bonyolult eljárások szükségesek, és ezek leegyszerűsítésére néhány programot helyeztek el a Kickstart és Workbenc könyvtáraiba. Ezek könnyen meghívható rutinokat tartalmaznak, melyekkel viszonylag könyebben el lehet érni a chipeket. Ha csak ezeket a könyvtárakat használják az Amiga programozásához, akkor a paraméterek ugyan azok, függetlenül a programozás nyelvtől, csak a paraméterek megnevezése változik nyelvről nyelvre. A BASIC ezek alól egy kivétel, a soronti parancsértelmező lefordítja a programhívásokat, ezért itt nem kell tudni, hogy az Amiga hogyan hajtja végre a különbőző funkciókat ahhoz, hogy aztán használni tudja őket. A könyvtári funkciók gépi kódban vannak írva, így szorosan összefűzhető a s aját gépi kódú programjaiddal. Igazából nélkülözni tudod a könyvtári függvényeket, és minden funkciót meg tudsz írni saját magad is, mindazonáltal ez annyival több munkát ró rád, hogy időnként jobban jársz ha mégis ezeket a függvényeket használod. 1.3.2. A memória. ----------------- Először nézzük meg az amiga 1000-er RAM-ját. Az standard verzó 512 kilobyte RAM- ot tartalmaz $00000 tól $7ffff-ig vagyis 0-524287. Ha a memóriát 1 Megabyte-ra bővítjük, akkor a kezdőcím még mindíg $000000 marad. az 512k byte feletti RAM-ok kezdőcíme azonban $200000-től $9FFFFF-ig tartanak, Az 1.2-es Amiga DOS kiadásoknál a memómira bővítés helyét egy speciális Autoconfig-ban adják meg. Chip RAM; A segédchipek amik az Amiga processzorát tehermentesítik, szintén hozzáférnek a RAM-hoz azonban ezek csak az alső 512k byte RAM-os tudják elérni, így a grafikák és a hangkeltéshez szükséges adatokat ezen a területen kell eltárolni. Ezt a RAM-ot ezért nevezik Chip RAM-nak. Fast RAM; A Chip RAM feletti RAM-okat nevezik fastramnak, (márha van a gépben ilyen), és ezek mint fent már egyszer le lett írva, de ez egy szájbarágós amerikai hülyegyerekeknek készült leírés, hát ide is leírjuk, $200000-től kezdődnek. Ezt a RAm terültet csak a processzor éri el, Íme az amiga memória felosztása: $000000-$07FFFF chip RAM $080000-$1FFFFF reserved $200000-$9FFFFF potential fast RAM $A00000-$BEFFFF reserved $BFD000-$BFDF00 PIA B (even addresses) $BFE001-$BFEF00 PIA C (odd addresses) $C00000-$DFEFFF reserved for expansion $DFF000-$DFFFFF custom chip registers $E00000-$E7FFFF reserved $E80000-$EFFFFF expansion ports $F00000-$F7FFFF reserved $F80000-$FFFFFF system ROM Mivel az Amiga multi-tasking rendszerű (több program futhat egy időben), ezért több program van egy időben a memóriában. Ha egy program betöltődik a memóriába, akkor azt a memóriatartományt hozzáadják a foglalt memóriatartomány listához, és ahhoz másik program nem férhet hozzá. Ha egy másik programot is megpróbálunk begyüszmékelni a memóriába, akkor az először megnézi ezt a listát. Probléma lehet, hogy az elsőnek betöltődött program igényelne még memóriát, pl. egy szövegbuffer miatt, és ez több mint amit először igényelt, és egy másik már lefoglalta azt a mögötte lévő memóriát. Az is probléma lehet, hogy ha az elsőnek betöltött program végez, és felsazabadítja a memóriát ahol dolgozott, akkor a RAM szabad és foglalt részekre tagolódik. Az Amiga amiga azonban ezeket a darabokat képes úgy kezelni mintha egy darab folyamatos memória lenne. Ennek egy nagyon szemléletes példája a dinamikus RAM disk, amit a rendszer RAM:-al jelöl. Ez a RAM úgy látszik, hogy mindíg teljesen fel van töltve (nem látható rajta űres terület, mert mérete nem meghatározott, dinamikusan változik). Ha egy fájlt letörölsz a RAM diskről, akkor az igy felszabadított terület hozzáadódik a rendszer számára elérhető memóriához, függetlenül attól, hogy az milyen struktúrájú volt. Ha erre a RAM diskre másolsz egy 100K bytos fájlt, akkor az valójában állhat több kicsi memóradarabból, összesen 100k byte méretben. (persze lehet hogy egybefüggő darab lesz, de az is lehet hogy apró darabkákból áll össze:50kb+5kb+15kb+30kb). Az Amiga soha nem ad információt erről, automatikusan állítja a látható és a valóságos memória méretét. 1.3.3. Multi-Task ----------------- Az amiga egy igazán csodálatos gép, képes egyszerre több dolgot is csinálni. Egy piros fehér labda pattog az egyik ablakban, miközben te szöveget szerkesztes egy második ablakban és az óra ketyeg a harmadikban. Ez az amiga erejének demonstrációja, és az emberek el is hiszik, hogy ezek egyszerre futnak. Az igazság azonbaz az, hogy az amiga csak egy processzort tartalmaz, és az egy időben csak egy dolgot csinál. A trükk az, hogy ha több program "egyszerre" fut, akkor az Amiga lépked a két program között, és amind a kettőt futtatja egy kicsit. A fenti példában a labda elmozdul egy pixelt, majd a processzor ellenőrzi, hogy gépeltek e be karaktert, ha igen akkor azt meg kell jeleníteni, majd odébmozgatja az óra mutatóját ha szükséges. Ezt a műveletsort ismételgeti folyamatosan amíg ez a 3 program fut. A probléma olyankor van, ha nagyon nagy programot töltünk be (vagy nagyons sok kicsit), és ilyenkor ez a folyamat lelassul, tehát a multitaszk alatt a programok lasabban futnak, mint egyedül. A task; A fenti feladatokat task-nak (taszk) nevezik, innne multi-tasking elnevezés. A multi task alatt minden task kap egy kis időszeletet ami alatt az adott task futhat. Ezek az időszeletek állíthatók, a több időt igénylő programoknak tudunk kicsit több processzoridőt adni, A programozónak ezzel az időosztással nem kell foglalkoznia. Megírod a programot, nem törődve azzal, hogy egy multi tsakos rendszerben fog futni, majd el tudod indítani párhuzamosan a már futó programokkal háttérben. Az egyedüli kitétel az, hogy a CLI (konzol) ablakban a run előtaggal indítsd el a programodat. Ha a CLI ablakba csak simán begépeled a programod nevét, akkor a processzor a CLI ablak időszeletét adja oda proghramodnak, és amíg a programod nem végzett a CLI nem kap új időszelete, azaz nem fog futni. Futtasd a run paranccsal a programodat, és ilyenkor új taszként saját időszelettel indul. Van néhány dolog, amit az assembler programozókank ajánlatos betartani a multitaszkos környezetben. Ha plusz memóriára van szükség, először foglald le. Amennyiben lehetséges ne módosítsd közvetlenül a hardver regsztereket.Lehetőség szerint használd könyvtári függvényeket. Egy kis egyszerű példa a fentiek szemléltetésére: Tegyük fel, hogy a nyomtató portot adatbevitelre használod. (asszem a kölső hangcuccok ilyenek) és onnan adatokat olvasol be, mikor is egy másik program gondol egyet és nyomtatni kezd. A vonalat átváltják kimeneti üzemmódra, és adatokat akarnak rajta kiküldeni. A programod megpróbál ezek után adatokat olvasni, azonban ez most már lehetetlen. Ez egy kissé erőltetett példa, de jól szemlélteti a problémát. Az igazi programozási helyzetekben a harver regiszterek többbszörös direkt programozása okozhat sok programösszeomlást. Ha mégis közvetlenül kell elérni a harverregisztereket (valamilyen advaned effekt miatt), akkor biztosítani kell, hogy a program ezalatt csak egyedül fusson.