Assembly programozás. szerkesztette: Iványi Péter. September 22, 2009



Hasonló dokumentumok
Assembly programozás. szerkesztette: Iványi Péter. September 27, 2010

Assembly utasítások listája

Számítógépek felépítése, alapfogalmak

Digitális rendszerek. Utasításarchitektúra szintje

Számítógépek felépítése

Számítógép felépítése

elektronikus adattárolást memóriacím

1. Az utasítás beolvasása a processzorba

Számítógépek felépítése, alapfogalmak

Assembly. Iványi Péter

Ismerkedjünk tovább a számítógéppel. Alaplap és a processzeor

A számok kiírása is alapvetően karakterek kiírásán alapul, azonban figyelembe kell venni, hogy a számjegyeket, mint karaktereket kell kiírni.

Assembly Utasítások, programok. Iványi Péter

Memóriák - tárak. Memória. Kapacitás Ár. Sebesség. Háttértár. (felejtő) (nem felejtő)

A számítógép egységei

A regiszterek az assembly programozás változói. A processzor az egyes mőveleteket kizárólag regiszterek közremőködésével tudja végrehajtani.

Bevezetés az informatikába

Operandus típusok Bevezetés: Az utasítás-feldolgozás menete

SZÁMÍTÓGÉPEK BELSŐ FELÉPÍTÉSE - 1

Informatika érettségi vizsga

Balaton Marcell Balázs. Assembly jegyzet. Az Assembly egy alacsony szintű nyelv, mely a gépi kódú programozás egyszerűsítésére született.

Adatok ábrázolása, adattípusok

Bepillantás a gépházba

Digitális technika VIMIAA01 9. hét Fehér Béla BME MIT

Digitális technika VIMIAA01 9. hét

2. Számítógépek működési elve. Bevezetés az informatikába. Vezérlés elve. Külső programvezérlés... Memória. Belső programvezérlés

5. tétel. A számítógép sematikus felépítése. (Ábra, buszok, CPU, Memória, IT, DMA, Periféria vezérlő)

A processzor hajtja végre a műveleteket. összeadás, szorzás, logikai műveletek (és, vagy, nem)

8. Fejezet Processzor (CPU) és memória: tervezés, implementáció, modern megoldások

Adatszerkezetek Tömb, sor, verem. Dr. Iványi Péter

5-6. ea Created by mrjrm & Pogácsa, frissítette: Félix

Számítógép Architektúrák

6. óra Mi van a számítógépházban? A számítógép: elektronikus berendezés. Tárolja az adatokat, feldolgozza és az adatok ki és bevitelére is képes.

IT - Alapismeretek. Feladatgyűjtemény

8. Fejezet Processzor (CPU) és memória: tervezés, implementáció, modern megoldások

A 32 bites x86-os architektúra regiszterei

A mikroszámítógép felépítése.

Programozás alapjai. 10. előadás

ELŐADÁS SZÁMÍTÓGÉP MŰKÖDÉSE FIZIKA ÉS INFORMATIKA

The Architecture of Computer Hardware and Systems Software: An InformationTechnology Approach 3. kiadás, Irv Englander John Wiley and Sons 2003

Gyakorló feladatok. /2 Maradék /16 Maradék /8 Maradék

Egyszerű RISC CPU tervezése

Kinek szól a könyv? A könyv témája A könyv felépítése Mire van szükség a könyv használatához? A könyvben használt jelölések. 1. Mi a programozás?

2. Fejezet : Számrendszerek

találhatók. A memória-szervezési modell mondja meg azt, hogy miként

Assembly programozás levelező tagozat

Architektúra, megszakítási rendszerek

Assembly Címzési módok. Iványi Péter

VI. SZOFTVERES PROGRAMOZÁSÚ VLSI ÁRAMKÖRÖK

Processzor (CPU - Central Processing Unit)

Bevezetés a számítástechnikába

1. Digitális írástudás: a kőtáblától a számítógépig 2. Szedjük szét a számítógépet 1. örök 3. Szedjük szét a számítógépet 2.

GPU Lab. 4. fejezet. Fordítók felépítése. Grafikus Processzorok Tudományos Célú Programozása. Berényi Dániel Nagy-Egri Máté Ferenc

A mikroprocesszor egy RISC felépítésű (LOAD/STORE), Neumann architektúrájú 32 bites soft processzor, amelyet FPGA val valósítunk meg.

Mintavételes szabályozás mikrovezérlő segítségével

A számítógépek felépítése. A számítógép felépítése

Alapismeretek. Tanmenet

VIRTUALIZÁCIÓ KÉSZÍTETTE: NAGY ZOLTÁN MÁRK EHA: NAZKABF.SZE I. ÉVES PROGRAMTERVEZŐ-INFORMATIKUS, BSC

Aritmetikai utasítások I.

sallang avagy Fordítótervezés dióhéjban Sallai Gyula

Adatelérés és memóriakezelés

A MiniRISC processzor

IT - Alapismeretek. Megoldások

A Számítógépek felépítése, mőködési módjai

Első sor az érdekes, IBM PC ra alapul: 16 bites feldolgozás, 8 bites I/O (olcsóbb megoldás). 16 kbyte RAM. Nem volt háttértár, 5 db ISA foglalat

1. ábra: Perifériára való írás idődiagramja

Assembly. Iványi Péter

Mi az assembly? Gyakorlatias assembly bevezető. Sokféle assembly van... Mit fogunk mi használni? A NASM fordítóprogramja. Assembly programok fordítása

Hardverközeli programozás 1 1. gyakorlat. Kocsis Gergely

Párhuzamos programozási platformok

Megoldás. Feladat 1. Statikus teszt Specifikáció felülvizsgálat

Hardver Ismeretek IA32 -> IA64

Informatika 1 2. el adás: Absztrakt számítógépek

Rekurzió. Dr. Iványi Péter

Algoritmusok és adatszerkezetek gyakorlat 06 Adatszerkezetek

Az interrupt Benesóczky Zoltán 2004

Számítógép architektúra

Nyíregyházi Egyetem Matematika és Informatika Intézete. Input/Output

1. Milyen eszközöket használt az ősember a számoláshoz? ujjait, fadarabokat, kavicsokat

Máté: Számítógép architektúrák

Multimédia hardver szabványok

Programozás II. 2. Dr. Iványi Péter

A Számítógépek hardver elemei

Párhuzamos programozási platformok

Számítógép fajtái. 1) személyi számítógép ( PC, Apple Macintosh) - asztali (desktop) - hordozható (laptop, notebook, palmtop)

Számítógép egységei. Szoftver (a fizikai eszközöket működtető programok összessége)

MEMÓRIA TECHNOLÓGIÁK. Számítógép-architektúrák 4. gyakorlat. Dr. Lencse Gábor. tudományos főmunkatárs BME Híradástechnikai Tanszék

Bevezetés a számítástechnikába

C programozási nyelv Pointerek, tömbök, pointer aritmetika

Központi vezérlőegység

Adatszerkezetek 1. Dr. Iványi Péter

Labor gyakorlat Mikrovezérlők

Mutatók és mutató-aritmetika C-ben március 19.

A fordítóprogramok szerkezete. Kódoptimalizálás. A kódoptimalizálás célja. A szintézis menete valójában. Kódoptimalizálási lépések osztályozása

Összeadás BCD számokkal

SzA19. Az elágazások vizsgálata

Járműfedélzeti rendszerek I. 3. előadás Dr. Bécsi Tamás

Dr. Wührl Tibor Ph.D. MsC 04 Ea. IP P címzés

A mikroprocesszor felépítése és működése

Digitális technika II. (vimia111) 5. gyakorlat: Tervezés adatstruktúra-vezérlés szétválasztással, vezérlőegység generációk

Átírás:

Assembly programozás szerkesztette: Iványi Péter September 22, 2009

2

Tartalomjegyzék 1 Bevezetés 9 1.1 Assembly elsőre...................................... 9 1.2 Miért tanuljunk assembly nyelvet?............................ 10 1.3 Mikor ne használjunk assembly nyelvet?......................... 11 1.3.1 A magas szintű programozási nyelvek előnye.................. 11 1.3.2 Az assembly hátrányai.............................. 12 1.4 Mielőtt elkezdenénk assembly-ben programozni...................... 12 1.5 Szintakszis........................................ 12 1.6 Assemblerek....................................... 12 1.6.1 MASM...................................... 13 1.6.2 GAS....................................... 13 1.6.3 TASM....................................... 13 1.6.4 NASM...................................... 13 1.6.5 Melyik assembler?................................ 13 1.7 Összefoglalás....................................... 13 1.8 Ellenőrző kérdések.................................... 13 2 A számítógép felépítése 15 2.1 A processzor....................................... 15 2.1.1 Végrehajtási ciklus................................ 16 2.1.2 A rendszer óra.................................. 17 2.2 Címzési architektúra................................... 17 2.2.1 Három címes architektúra............................ 17 2.2.2 Két címes architektúra.............................. 18 2.2.3 Egy címes architektúra.............................. 18 2.2.4 Zéró cím architektúra............................... 18 2.2.5 Load/Store architektúra.............................. 18 2.3 Regiszterek........................................ 19 2.4 Végrehajtási sorrend................................... 19 2.4.1 Branching..................................... 19 2.5 Memória.......................................... 20 2.5.1 Memória műveletek............................... 20 2.5.2 Olvasási ciklus.................................. 20 3

2.5.3 Olvasási ciklus.................................. 21 2.5.4 Memória típusok................................. 21 2.5.5 Byte sorozatok tárolása.............................. 22 2.5.6 Adat alignment problema........................... 23 2.6 Input/Output........................................ 24 2.6.1 I/O eszközök elérése............................... 25 2.7 Összefoglalás....................................... 25 2.8 Ellenőrző kérdések.................................... 25 3 A processzor 27 3.1 Általános regiszterek................................... 28 3.2 Szegmentált címzés először................................ 28 3.3 Címzési módok...................................... 29 3.3.1 Direkt címzési mód................................ 31 3.3.2 Indirekt címzési mód............................... 32 3.4 Státusz regiszter...................................... 33 3.5 Ellenőrző kérdések.................................... 34 4 NASM assembler 35 4.1 Egy forrás file szerkezete................................. 35 4.2 Pszeudo utasítások.................................... 35 4.2.1 DB és társai.................................... 36 4.2.2 RESB és társai.................................. 36 4.2.3 Konstansok.................................... 37 4.2.4 TIMES pszeudo utasítás............................. 37 4.3 SEG kulcsszó....................................... 37 4.3.1 További hasznosítási területek.......................... 38 4.4 WRT kulcsszó....................................... 38 4.5 Parancssori opciók.................................... 38 4.6 Hibaüzenetek....................................... 38 5 DEBUG program 39 5.1 Jelölések.......................................... 39 5.2 A DEBUG indítása.................................... 39 5.3 A DEBUG parancsai................................... 39 5.4 Példák........................................... 42 5.4.1 1. Példa...................................... 42 5.4.2 2. Példa...................................... 42 5.4.3 3. Példa...................................... 43 6 Első programok 45 6.1 Első program....................................... 45 6.2 Egy karakter kinyomtatása................................ 46 6.3 Egy szöveg kinyomtatása................................. 47 4

6.4 Egy karakter beolvasása.................................. 49 7 Assembly nyelv utasításai 51 7.1 Adatmozgató utasítások.................................. 52 7.1.1 MOV....................................... 52 7.1.2 XCHG...................................... 52 7.1.3 XLAT....................................... 53 7.1.4 LDS........................................ 53 7.1.5 LES........................................ 53 7.1.6 LEA........................................ 54 7.1.7 PUSH....................................... 54 7.1.8 PUSHF...................................... 54 7.1.9 PUSHA...................................... 55 7.1.10 POP........................................ 55 7.1.11 POPF....................................... 55 7.1.12 POPA....................................... 56 7.1.13 LAHF....................................... 56 7.1.14 SAHF....................................... 57 7.2 Matematikai utasítások.................................. 58 7.2.1 INC........................................ 58 7.2.2 DEC....................................... 58 7.2.3 ADD....................................... 58 7.2.4 ADC....................................... 59 7.2.5 SUB........................................ 59 7.2.6 SBB........................................ 60 7.2.7 MUL....................................... 60 7.2.8 IMUL....................................... 61 7.2.9 DIV........................................ 61 7.2.10 IDIV....................................... 62 7.2.11 NEG....................................... 62 7.2.12 CBW....................................... 63 7.2.13 CWD....................................... 63 7.3 Bitforgató és bitléptető utasítások............................. 64 7.3.1 RCL........................................ 64 7.3.2 RCR....................................... 64 7.3.3 ROL........................................ 65 7.3.4 ROR....................................... 66 7.3.5 SAL, SHL.................................... 66 7.3.6 SAR........................................ 67 7.3.7 SHR........................................ 67 7.4 Logikai utasítások..................................... 69 7.4.1 AND....................................... 69 7.4.2 OR........................................ 69 5

7.4.3 XOR....................................... 69 7.4.4 NOT....................................... 69 7.4.5 TEST....................................... 69 7.4.6 CMP....................................... 69 7.5 Vezérlésátadó utasítások................................. 70 7.5.1 JMP........................................ 70 7.5.2 Feltételes utasítások............................... 70 7.5.3 JCXZ....................................... 70 7.5.4 LOOP....................................... 70 7.5.5 LOOPNZ..................................... 70 7.5.6 LOOPZ...................................... 70 7.5.7 CALL....................................... 70 7.5.8 RET........................................ 70 7.5.9 INT........................................ 70 7.6 String kezelő utasítások.................................. 71 7.6.1 MOVSB, MOVSW................................ 71 7.6.2 CMPSB, CMPSW................................ 71 7.6.3 LODSB, LODSW................................ 71 7.6.4 STOSB, STOSW................................. 71 7.6.5 SCASB, SCASW................................. 71 7.6.6 REP........................................ 71 7.6.7 REPZ....................................... 71 7.6.8 REPNZ...................................... 71 7.7 Processzor vezérlő utasítások............................... 72 7.7.1 CLC........................................ 72 7.7.2 STC........................................ 72 7.7.3 CMC....................................... 72 7.7.4 CLD....................................... 72 7.7.5 STD........................................ 72 7.7.6 CLI........................................ 72 7.7.7 STI........................................ 72 7.8 Egyéb utasítások..................................... 73 7.8.1 NOP....................................... 73 7.8.2 IN......................................... 73 7.8.3 OUT....................................... 73 7.9 Ellenőrző kérdések.................................... 74 8 Assembly programokról 77 8.1 Programozási módszer.................................. 77 8.2 Megszakítások...................................... 77 8.3 COM programok..................................... 77 8.3.1 Program Segment Prefix............................. 78 8.4 EXE programok...................................... 78 6

8.5 XOR használata...................................... 78 8.6 Assembly integer aritmetika............................... 78 8.6.1 BCD aritmetika.................................. 78 9 Példa programok 79 9.1 Egy byte bináris kinyomtatása.............................. 79 9.2 Egy hexadecimális szám kinyomtatása.......................... 81 9.3 Egy byte hexadecimális kinyomtatása.......................... 83 9.4 Egy decimális számjegy ellenőrzött beolvasása és kinyomtatása............. 85 9.5 Egy karakter beolvasása és módosítása.......................... 86 9.6 Öt karakter bolvasása és kinyomtatása fordított sorrendben............... 88 9.7 Két egyjegyű szám összeadása.............................. 89 9.8 Egy karakter n-szeri kinyomtatása............................ 92 9.9 Téglalap kinyomtatása.................................. 93 9.10 Sakktábla nyomtatása................................... 96 9.11 ASCII tábla kinyomtatása................................. 99 9.12 Szám kiírása decimális formában............................. 100 9.13 Olvasás a memóriából................................... 102 9.14 Közvetlen videó memóriába írás............................. 103 9.15 Szöveg beolvasása.................................... 104 9.16 Beolvasott szövegben karakterek számlálása....................... 105 9.17 Beolvasott szöveg nagy betűsre konvertálása....................... 106 9.18 Feladatok......................................... 107 10 Speciális programok 109 10.1 Hardware vezérlés..................................... 109 10.2 Zenélő program...................................... 109 10.3 Memória rezidens programok............................... 109 10.4 Vírusok.......................................... 109 11 Megjegyzések 111 11.1 Szokásos hibák...................................... 111 A ASCII táblázat 113 B Felhasznált irodalom 115 Példa programok listája..................................... 116 Tárgymutató........................................... 117 7

8

1. Fejezet Bevezetés Ez a jegyzet inkább egy összeállítás, szerkesztett jegyzet, mint egy önálló könyv. A jegyzet anyagát több helyről szedtem össze, de azokat igyekeztem egy egységes egésszé összegyúrni. A felhasznált irodalom listája a jegyzet végén található. Az összeállítás célja az assembly nyelv megismertetése a hallgatókkal. Ugyanakkor az assembly nyelv nagyon erősen kötődik a processzor architektúrához. A processzor architektúrák két nagy csoportba sorolhatók: CISC (Complex Instruction Set Computers) 1, RISC (Reduced Instruction Set Computers) 2. A domináns processzor architektúra a piacon a Pentium processzor, ami a CISC családhoz tartozik, de ugyanakkor a jelenlegi trendek szerint egyre inkább a RISC architektúra kerül előtérbe. A RISC processzorok közé tartoznak a MIPS, SPARC, PowerPC és ARM processzorok. A 64-bites Itanium is RISC alapú processzor. Mit jelent az, hogy komplex utasítás? Két szám összeadása egyszerű műveletnek számít. Ugyanakkor, ha egy tömböt átmásolunk és közben a tömb mutatókat folyamatosan frissítjük, az már komplex utasításnak számít. 3 A RISC rendszerek csak egyszerű utasításokat használnak, és bizonyos feltételeket is szabnak. Például az utasítások argumentumainak a regiszterekben kell lenniük és nem a memóriában. 1.1 Assembly elsőre Az assembly nyelven írt programokat processzálni kell egy másik program, assembler, által ami gépi kódot generál. A gépi kódot fogja futtatni a processzor. Nézzünk néhány assembly utasítást: inc result mov meret, 45 add mask1, 256 Az első sorban megadott utasítás megnöveli a result változó értékét. A második sorban megadott utasítás a 45-ös értéket töltia mérett változóba, míg a harmadik utasítás 256-ot add a mask1 változóhoz. A fenti kódrészlet C programozási nyelven a következőképpen néz ki: result++; meret = 45; mask1 = mask1+ 256; A példá alapján a következőket lehet megállapítani az assembly nyelvről: Az assembly nyelv utasításai kriptikusak. 1 Szabad fordításban: Komplex utasításkészletű számítógép 2 Szabad fordításban: Egyszerűsített utasításkészletű számítógép 3 Itt kell megjegyezni, hogy létezik ilyen utasítás a CISC processzorokon, ez a MOVSB utasítás. 9

Pentium processzor Assembly Művelet Gépi kód (hex) nop Üres művelet 90 inc result Növelés FF060A00 mov result, 45 Másolás C7060C002D00 and mask, 128 Maszkolás 80260E0080 MIPS processzor Assembly Művelet Gépi kód (hex) nop Üres művelet 00000000 mov $t2, $t15 Másolás 000A2021 and $t2, $t1, 15 Logikai ÉS 312A000F addu $t3, $t1, $t2 Összeadás 012A5821 1.1. tábla: Assembly parancsok és a megfelelő gépi kód Az assembly nyelv műveleteit mnemonikok írják le, például add vagy mov. Az assembly nyelv utasításai nagyon alacsony szintűek. Például a következőt már nem írhatjuk le 4 : mov meret, adat A 1.1. táblázat néhány assembly utasítást és a neki megfelelő gépi kódot mutatja. A táblázatnál az első észrevétel, hogy a RISC processzorokon az utasítások hossza fix. (Ezzel is csökkentve a komplexitást.) A másik fontos észrevétel, hogy a gép kód megértése nagyon nehéz az emberek számára, hiszen több ezer szám kombinciót kellene megjegyezni. Ugyanakkor közvetlen, egy az egyes megfeleltetés van az assembly utasítás és a gépi kód között ezért ha az utasítást írjuk le az pontosan megfelel a szándék szerinti gépi kódnak és így csak mazochisták programoznának gépi kódban. Mindenki inkább az emberek számára jobban értelmezhető assembly parancsokat használja. Persze a digitális forradalom elején néhány programot még gépi kódban írtak. 1.2 Miért tanuljunk assembly nyelvet? Az assembly programozás nem annyira népszerű mint néhány éve volt. Ugyanakkor még mindig több oka van annak, hogy megtanuljunk assembly-ben programozni: Tanulás: Fontos tudni hogyan működnek a processzorok és fordítók az utasítás szinten. Ezen ismeretek segítségével meg lehet állapítani mely programozási módok a leghatékonyabbak, illetve, hogy a magasabb szintű programozási szerkezetek hogyan működnek. Debuggolás: Több szempontból is hasznos lehet ha a fordítók által generált kódot meg tudjuk érteni illetve meg tudjuk állapítani, hogy mennyire jó, optimalizált kódot generál egy fordító. Fordítók: Az assembly kód megértése elengedhetetlen ahhoz, hogy fordítót, debugger-t vagy egyéb fejlesztő eszközöket fejlesszünk. Beágyazott rendszerek: A beágyazott rendszereknek nincs annyi erőforrása mint egy hagyományos PC-nek és az assembly nyelvre szükség lehet, hogy ilyen rendszerekre gyors és hatékony kódot írjunk. 4 A magyarázat a 3. fejezetben található. 10

Hardware eszközök: A magas szintű programozási nyelvek korlátozott (absztrakt) hozzáférést engednek a hardware elemekhez, így a hardware eszközök használatát és elérését biztosító eszközvezérlőt írni magas szintű nyelven nehéz vagy lehetetlen. Ilyen esetben is jól jöhet az assembly nyelv ismerete. Olyan utasításokat is használhatunk assembly-ben aminek a magasabb szintű nyelvekben nincs megfelelője. Méretre való optimalizálás: A méretre való optimalizálás azt jelenti, hogy Program A kevesebb helyet foglal mint Program B de ugyanazt a feladatot látja el. A memória ma már olyan olcsó, hogy tulajdonképpen nem éri meg assembly-ben kódot írni a program méretének csökkentése miatt. Ugyanakkor a cache még midig kis méretű és drága, így az erre optimalizált kód esetén még mindig fontos az assembly nyelv használata. Sebességre való optimalizálás: A sebességre optimalizált program a lehető legrövidebb idő alatt végzi el a feladatot. Habár a modern fordítók viszonylag jól optimalizálják a generált kódot, bizonyos esetekben a kézzel optimalizált assembly program részlet drámaian fel tudja gyorsítani a programot. Az utolsó két szempontból az utóbbi a fontosabb. Egyrészt a hely megtakarítás csak a program kódra vonatkozik és az adatra nem, másrészt a memória méretének növekedése miatt. Assemblyben azért lehet hatékony kódot írni, mivel a nyelv sajátossága, hogy a generált kód csak azt tartalmazza amit beleírtunk, vagyis ami a feladat megoldásához kell. Semmi más, extra információt nem fordít bele az assembler. A sebességre optimalizált alkalmazások két kategóriába sorolhatók: idő hatékony alkalmazások: ezeknél a programoknál a gyorsabb futás jelent előnyt, de nincs különösebb probléma ha a sebesség lassabb; idő kritikus alkalmazások: ebben az esetben a feladatot adott idő alatt kell elvégezni. Általában ezek a valós idejű alkalmazások (real-time systems), például: repülőgép navigációs eszköz, robot kontroll rendszerek, kommunikációs szoftverek. 1.3 Mikor ne használjunk assembly nyelvet? Olyan sok hátránya van az assembly nyelven való programozásnak, hogy mielőtt elkezdenénk programozni assembly-ben más alternatívákat is vegyünk figyelembe. 1.3.1 A magas szintű programozási nyelvek előnye A magas szintű programozási nyelvek viszonylag kényelmes absztrakciót tesznek lehetővé, hogy az adott problémát megoldjuk. A magas szintű programozási nyelvek előnyei: A program fejlesztés gyorsabb: A magas szintű programozási nyelvekben sokféle programozási konstrukció áll rendelkezésre. Általában rövidebbek is a programok. A programokat könnyebb karbantartani: A magas szintű programozási nyelven írt programokat egyszerűbb megérteni és ezért könnyebb mások által írt programot áttekinteni és megérteni. A programok hordozhatóak: A program nem tartalmaz processzor specifikus részleteket és ezért bármilyen rendszeren használhatóak. 5 5 Itt főleg a forráskódról beszélünk, nem a futtatható, már lefordított gépi kódú programról. 11

1.3.2 Az assembly hátrányai Az assembly-ben való programozás ellen szóló legfontosabb érvek: 1. Fejlesztési idő: Az assembly-ben való programozás szinte mindig több időt igényel mint a magasabb szintű programozási nyelv használata. 2. Megbízhatóság és biztonság: Assembly nyelven könnyű hibát véteni. Az assembler csak szintaktikai ellenőrzéseket végez. 3. Debuggolás és ellenőrzés: Az assembly nyelven írt programokban nehezebb hibát keresni, illetve nehezebb ellenőrizni a kódot, hogy az előírt feladatot oldja meg. 4. Karbantartás: Az assembly nyelven írt programokat nehezebb módosítani és karbantartani. A nyelv megengedi a spagetti kód írási technikát és egyéb trükkök is megengedettek a nyelvben, melyeket más nyelven nem lehet megvalósítani. 5. Hordozhatóság: Az assembly kód a hardware platformhoz kapcsolódik, csak az adott processzoron, architektúrán lehet lefuttatni. 6. Modern fordítók: A modern fordítók sokat fejlődtek az elmúlt években és már nagyon jó kódot tudnak generálni és gyakran nehezebb jobb assembly kódot generálni. 1.4 Mielőtt elkezdenénk assembly-ben programozni... Van néhány szempont amit figyelembe kell venni mielőtt egy komplex alkalmazást elkezdenénk assemblyben programozni: Ha az a célunk, hogy egy program sebességét optimalizáljuk, akkor először azonosítsuk, hogy a program mely része fut a legtöbbet a processzoron. Ellenőrizzük, hogy mivel tölti a legtöbb időt a program, például a memória eléréssel, CPU utasítások végrehajtásával, file-ok elérésével vagy valami mással. Döntsük el, hogy a fejlesztett program újrahasznosítható vagy csak egy egyedi alkalmazás. Ha a kódot újra fel akarjuk használni, akkor érdemes több időt tölteni az optimalizálással. El kell dönteni, melyik assemblert használjuk, mivel a különböző assemblerek más-más szintakszist használhatnak. A jelentős mértékben optimalizált kódot nehéz lehet olvasni, így a karbantartás miatt érdemes kisebb egységekbe szervezni a programot melyeknek jól definiált interface-e van és megfelelően van dokumentálva. 1.5 Szintakszis Kétféle jelentősebb szintakszis alakult ki az évek során, amiket az assembly programok írásánál használhatunk: AT&T szintakszis Intel szintakszis 1.6 Assemblerek Több assembler is létezik az Intel processzorokra, melyek az x86-os utasítás készletet használják, vagyis a mnemonikokból Intel gépi kódot hoznak létre. Az alábbiakban csak néhányat mutatunk be. 12

1.6.1 MASM Ez a Microsoft Assembler, mely a mai napig része a Microsoft fejlesztő környezetének, a Visual Studionak. A program neve: ml.exe. A MASM sokáig a de-facto ipari szabvány volt és több magasabb szintű programozási konstrukciót is tudott kezelni. A formátuma nem teljesen tiszta, vannak inkonzisztens részek benne. Microsoft továbbra is fejleszti, de igazából minimális módon. 1.6.2 GAS GAS rövidités megfelelője a GNU Assembler, mely a GNU binutils csomag része is. A GNU fordítók olyan formátumot generálnak, melyet ez az assembler képes lefordítani. GAS az úgynevezett AT&T szintakszist használja, bár ma már az Intel szintakszisnak megfelelő kódot is el tud fogadni. Ez az assembler használható Linux, Mac OS X és Windows alatt is. 1.6.3 TASM Az egyik legnépszerűbb fejlesztői eszközöket a Borland cég készítette. Az általuk készített programfejlesztő családba tartozik a Turbo Assembler is. Sajnos ma már nem fejlesztik, az újabb utasítások nem kerülnek bele, de még mindig elérhető az Interneten. Az assembler által használt szintakszis nagyon hasonló a MASM assembler szintakszisához. 1.6.4 NASM NASM megfelel a Netwide Assembler névnek és egy szabad forráskodú assembler, mely többféle objektum formátumot képes generálni és így több operációs rendszert támogat (Linux, Windows, Mac OS X, FreeBSD, stb). A szintakszisa tisztább mint a MASM assembler-é, de kevesebb magas szintű programozási konstrukciót képes kezelni. 1.6.5 Melyik assembler? Ez a jegyzet a NASM assemblert használja két fő ok miatt: Az egyszerű szintakszis nagyon logikus és konzisztens. Windows és Linux rendszeren is használható, melyek manapság a legjobban elterjedt operációs rendszerek. 1.7 Összefoglalás Az assembly nyelv tanulása mind gyakorlati és pedagógia célokat szolgálhat. Még ha nem is szándékozunk assembly-ben programozni, akkor is érdemes megtanulni, mivel egy nagyon jó alapot ad ahhoz hogy megértsük, hogyan működnek a számítógépek. Amikor magas szintű programozási nyelvet használunk, akkor a rendszert egy fekete dobozként kezeljük. Ezzel szemben assembly programozás esetén a rendszert részleteit is ismerni kell, például a regisztereket. 1.8 Ellenőrző kérdések 1. Soroljon fel különböző processzorokat! 2. Mit jelent a CISC kifejezés és mi jellemző az ilyen processzorokra? 13

3. Soroljon fel indokokat miért érdemes assembly nyelvet tanulni? 4. Soroljon fel indokokat mikor kell assembly nyelvet tanulni? 5. Soroljon fel indokokat mikor ne használjunk assembly nyelvet? 6. Mi az assembly nyelv és a gépi kód kapcsolata? 7. Magas szintű programozási nyelvben miért nem tudjuk teljes mértékben kontrollálni a hardwaret? 8. Miért hívjuk az assembly programozási nyelvet alacsony szintű nyelvnek és a C programozási nyelvet magas szintűnek? 9. Soroljon fel néhány különbséget a CISC és RISC processzorok között? 10. Hasonlítsa össze a két féle assembly szintakszist! 11. Soroljon fel assemblereket! 12. Miért lehet szükség az assembly használatára idő kritikus alkalmazások esetén? 13. Soroljon fel idő kritikus alkalmazásokat! 14

2. Fejezet A számítógép felépítése A számítógépnek alapvetően három fő komponense van: a központi egység vagy processzor (CPU), a memória, és az Input/Output eszközök. Lásd a 2.1. ábra. A részek közötti kapcsolatot a rendszer busz biztosítja. A memória tárolja a programokat és az adatokat is egyszerre. Az Input/Output eszközök lehetnek a billentyűzet, a képernyő és így tovább. A 2.2. ábra egy részletesebb nézetét adja a számítógépnek, ahol jól látható hogy a rendszer busz három részből áll: cím busz, adat busz és kontroll busz. A cím busz szélessége határozza meg az elérhető memória kapacitást, illetve az adat busz adja meg, hogy milyen méretű adatok mozoghatnak a CPU, a memória és az I/O eszközök között. Például a 8086-os processzornak 20 bites a cím busza és 16 bites az adat busza. Ezek alapján a processzor 2 20 byte-ot tud megcímezni, vagyis 1 MByte-ot és minden alkalommal 16 bit mozog az egységek között. A Pentium processzoroknak 32 cím vonaluk van a cím buszban és 64 adat vonala. Így a Pentium 4 GByte memóriát tud megcímezni. A 2.2. ábrán az is fontos, hogy a buszok milyen irányba képesek adatot küldeni. Látható, hogy a CPU a kontroll buszon keresztül ad utasításokat a memóriának és az I/O alrendszernek, adatot viszont az adat buszon keresztül fogad. A kontroll buszon kiadható jelek: memória olvasás, memória írás, I/O olvasás, I/O írás, megszakítás és így tovább. 2.1 A processzor A processzor kontrollálja a legtöbb tevékenységet a rendszerben. Úgy érdemes rá gondolni, hogy a következő ciklust hajtja végre: 1. Egy utasítás betöltése a memóriából (fetch), 2. Az utasítás dekódolása, azonosítása (decode), CPU Memória Kapcsolat Input/Output 2.1. ábra: Absztrakt értelmezése a számítógépnek 15

CPU Memória Cím busz Adat busz Kontroll busz I/O alrendszer 2.2. ábra: Egy számítógép egyszerűsített diagramja 3. Az utasítás végrehajtása (execute). Ez a végrehajtási ciklus, vagy fetch-decode-execute ciklus. 2.1.1 Végrehajtási ciklus Fetch Decode Execute A processzor a betöltendő utasítás címét felrakja a cím buszra. A processzor a kontroll buszon keresztül memória olvasásra ad utasítást a memória egységnek. A processzor addig vár amíg az utasítás meg nem jelenik az adat buszon. A memória egységnek idő kell míg hozzáfér a szükséges részhez. Ez a hozzáférési idő. A memória a beolvasott utasítást az adat buszra helyezi. A processzor beolvassa az adat buszról az utasítást Azonosítani kell a beolvasott utasítást. Ezt segítendő az utasítások bizonyos kódolási mintát követnek, melyet majd a 7. fejezetben tárgyalunk. A végrehajtáshoz két egységre van szükség: egy kontrol és egy aritmetikai (ALU) egységre. A kontroll egység segít az időzítésben, míg az ALU egység a matematikai számításokat végzi el. Megjegyezzük, hogy az adatok és az utasítások nem mindig közvetlenül a memóriából jönnek, hanem az úgynevezett cache-ből. A cache memóriához való hozzáférés gyorsabb. A Pentium processzoron 16 KB-os cache van a chipen, melynek fele adat és fele utasítás cache. Szerencsére a cache használata hardware-ben van megoldva és teljesen transzparens a programozó számára. 16

2.1.2 A rendszer óra A rendszer óra a system clock. A rendszer óra teszi lehetővé, hogy a műveleteket összeszinkronizáljuk. Az órajel 1-eseket és 0-kat ad ki sorozatban, szekvenciában. Az óra frekvencia értékét a másodpercenkénti ciklusok száma adja meg és a mértékegysége Hertz (Hz). A MHz és GHz 10 6 és 10 9 ciklust jelent másodpercenként. 1 óra frekvencia = (2.1) óra ciklus hossza A rendszer óra adja meg a számítógép sebességét. Minden processzor művelet végrehajtása több órajel ciklust igényel. Például egy 1 GHz-es Pentium processzoron egy adat továbbítása a memóriából a processzorra három órajel ciklust igényel. Egy óra ciklus hossza: és így az adattovábbításhoz 3 ns-ra van szükség. 1 = 1ns (2.2) 1 109 A számítógépek sebességét növelhetjük úgy, hogy nagyobb órajel frekvenciát használunk. Például egy 2 GHz-es processzoron az adat továbbítás már csak 1.5 ns-ig fog tartani. 2.2 Címzési architektúra Érdekes módon az egyik legfontosabb tulajdonsága egy architektúrának hogy hány címet használunk az utasításokban. A legtöbb művelethez egy vagy két argumentumra van szükség. Ezek alapján szokták a műveleteket binary és unary műveleteknek nevezni, ahol a a bi- kettőt, az un- egyet jelent. Unary művelet például a tagadás (NOT) művelet, míg binary művelet az összeadás és a kivonás. Ezek a műveletek egy eredményt adnak. Természetesen vannak kivételek, például az osztás. Az osztásnál két argumentumra van szükség, az osztandóra és az osztóra, viszont két eredmény is keletkezik: az eredmény és a maradék. Mivel a binary műveletek a leggyakoribbak és ebben az esetben két input argumentumra és egy eredmény, output argumentumra van szükség ezért ezért általában három címre van szükség egy utasításnál. Ebben a részben azt nézzük meg, hogyan lehet három, kettő, egy és zérus címet használni az utasításokkal. 2.2.1 Három címes architektúra A három címet használó utasításkészlettel rendelkező processzoroknál a két input argumentumot és az egyetlen output argumentumot tudjuk megadni. A legtöbb modern processzor ilyen utasításkészletet használ. Nézzünk egy példát: A = B + C * D - E + F + A mely pszeudo assembly-ben a következőképpen néz ki: mult T,C,D ; T = C * D add T,T,B ; T = B + C * D sub T,T,E ; T = B + C * D - E add T,T,F ; T = B + C * D - E + F add A,A,T ; A = B + C * D - E + F + A A példában az látható, hogy matematikai műveletre egy utasítást kell megadni. Ami szintén szembetűnő, hogy az első utasítást kivéve az első két argumentum azonos. Mivel az esetek jelentős részében így van, ezért a sok duplikáció elkerülése végett két-címes utasításkészleteket is szoktak implementálni processzorokban. 17

2.2.2 Két címes architektúra Ebben az esetben az utasításoknak csak cím argumentuma van és az egyik cím inputként és outputként is szolgál. Az Intel processzorok, például a Pentium is ilyen utasításokat használ. Nézzük az előző példát újra: A = B + C * D - E + F + A mely pszeudo assembly-ben a következőképpen néz ki: load T,C ; T = C mult T,D ; T = C * D add T,B ; T = B + C * D sub T,E ; T = B + C * D - E add T,F ; T = B + C * D - E + F add A,T ; A = B + C * D - E + F + A Mivel csak két argumentum áll rendelkezésre ezért az első utasítással betöltjük az adatot T-be. Ebben az esetben az a feltűnő, hogy az első 6 utasításban a T argumentum közös. Ha ez lesz az alap eset, akkor már csak egy cím, argumentum kell az utasításokhoz. 2.2.3 Egy címes architektúra Ha a memória drága vagy lassú akkor egy speciális regisztert használ a processzor. Ez a regiszter szolgáltatja az input és az output argumentumot egy utasításnak. Ezt a regisztert akkumulátor regiszternek is szokták nevezni, mivel benne gyűlik össze, akkumulálódik, az eredmény. A legtöbb arhitektúra esetén csak egy akkumulátor regiszter van. Ezt a regisztert nem kell megadni az utasításnak csak a másik argumentumot. 2.2.4 Zéró cím architektúra Arra is van lehetőség, hogy mindkét argumentum speciális helyen tárolódik és így nem kell megadni őket az utasításoknál. Ezek a processzorok egy vermet használnak. Az argumentumok a verem tetején vannak amiket az utasítás levesz onnan, majd az eredményt is a verem tetejére teszi vissza. 2.2.5 Load/Store architektúra Ebben az esetben a műveleteket a processzor belső regiszterein végezhetjük el és külön utasítással kell beolvasni az adatokat a memóriából a regiszterekbe, illetve a regiszterekből kiírni a memóriába. A fenti példa a következőképpen módosul: A = B + C * D - E + F + A mely pszeudo assembly-ben a következőképpen néz ki: load R1,B load R2,C load R3,D load R4,E load R5,F load R6,A mult R2,R2,R3 ; R2 = C * D add R2,R2,R1 ; R2 = B + C * D 18

sub R2,R2,R4 ; R2 = B + C * D - E add R2,R2,R5 ; R2 = B + C * D - E + F add R2,R2,R6 ; R2 = B + C * D - E + F + A store A,R2 A fenti példában hat regisztert is használunk. Bár nincs ennyire szükség, de ez általában jellemző ezekre az architektúrákra, hogy sok regiszterük van. A RISC processzoroknak több regiszterük van mint a CISC processzoroknak. A MIPS processzornak 32 regisztere van, az Intel Itanium processzornak 128 regisztere és az Intel Pentium processzornak csak 10 regisztere van. 2.3 Regiszterek Minden processzorban vannak regiszterek, melyeket két fő csoportba sorolhatunk: általános célú regiszterek, speciális célú regiszterek. A speciális célú regisztereket további két csoportba oszthatjuk: felhasználó által elérhető regiszterek és csak a rendszer által elérhető regiszterek. A Pentium regisztereit a 3. fejezetben tárgyaljuk. 2.4 Végrehajtási sorrend A program végrehajtása általában szekvenciálisan történik, az utasításokat egymás után hajtjuk végre. Az egyik regiszter, a Program Counter (PC) vagy Instructon Pointer (IP) regiszter, fontos szerept játszik a végrehajtási sorrend kezelésében. A processzor mindig azt az utasítást tölti be (fetch) amire a PC regiszter mutat. A betöltés után a PC regiszter értékét megnöveljük, hogy a következő utasításra mutasson. Ez a megnövelés lehet fix méretű, például a RISC processzoroknál, vagy változó méretű a CISC processzoroknál, ahogy ez látható a 1.1. A CISC processzorok esetén minden utasításnál külön meg kell állapítani, hogy mennyivel növeljük meg a PC regiszter értékét. A magasabb szintű programozási nyelvekben ugyanakkor vannak feltételes végrehajtási és ciklikus programozási konstrukciók, melyek a végrehajtási sorrendet változtatják meg valamilyen futás közbeni feltételtől függően. Ezek megvalósítása a processzorokban speciális módon történik. 2.4.1 Branching A branching szó fordítása talán az elágazás lehet. Arról van szó, hogy az eredeti szekvenciát megszakítva, máshol folytatódik a program végrehajtása. Két változata van: a feltétel nélküli és feltételes ugró utasítás. Ezeknek az utasításoknak egy argumentuma van, mely explicit módon megadja az új utasítás címét. Ez azt jelenti, hogy amikor máshol kell folytatni a végrehajtást, akkor a PC regiszterbe az új címet töltjük be és így a következő fetch -nél már ezt a címet fogja használni a processzor. A végrehajtási sorrend a feltétel nélküli ugró utasítás esetén a 2.3. ábrán látható. Feltételes ugrás A feltételes ugrás esetén az új cím csak akkor töltődik be a PC regiszterbe, ha valamilyen feltétel teljesül. Kétféle módon szokták ezt megadni a különböző processzorokban: Set-Then-Jump : Az ilyen architektúrájú processzorokban a vizsgálat és az ugrás szét van választva. A két, különálló rész közötti kapcsolatot egy regiszter biztosítja. A vizsgálat beállítja a regiszter értékét, majd az ugró utasítás ezt a regisztert vizsgálja meg hogy bekövetkezzen-e az ugrás vagy sem. A Pentium processzorok ezt a technikát használják. 19

utasítás jump utasítás a cím b utasítás utasítás c d 2.3. ábra: Ugró utasítás Test-And-Jump : A legtöbb processzor összekombinálja a két részt, például a MIPS processzorok. Például: beq Rsrc1, Rsrc2, célcím összehasonlítja az Rsrc1 és Rsrc2 regiszterek tartalmát és ha egyenlőek, akkor a célcím-nél folytatódik a végrehajtás. 2.5 Memória A számítógép memóriáját úgy érdemes elképzelni mint sok elektronikus kapcsoló összessége. Ezek a kapcsolók két állapotban lehetnek: nyitott vagy zárt állapotban. Ugyanakkor ezeket az állapotokat érdemesebb 1 és 0 állapottal jellemezni. Így minden kapcsolót reprezentálni lehet egy bináris számmal vagy bittel. A memória millió szám tartalmaz biteket. A jobb kezelhetőség miatt a memória a biteket csoportokba szervezik. 8 bit csoportja egy byte. Így a memória mint egy byte sorozat képzelhető el. Minden byte-ra egy index számmal lehet hivatkozni. Az első index értéke 0. Az utolsó index értéke 2 n 1, ahol az n az adatbusz szélessége (hány bites). A memória sematikus képe a 2.4. ábrán látható. 2.5.1 Memória műveletek Két alapvető művelet van: adat olvasás a memóriából és adat írás a memóriába. Mindkét esetben szükség van egy memória címre ahonnan olvashatunk, vagy ahova írhatunk. Ezenkívűl az írási művelet még egy adatot is igényel. 2.5.2 Olvasási ciklus 1. A processor elhelyezi az olvasandó adat címét a cím buszon. 2. A kontroll buszon a processzor kiadja a memória olvasási jelet. 3. A processzor várakozik amíg az olvasás megtörténik és az adat megjelenik az adat buszon. 4. A processzor beolvassa az adatot az adat buszról. 20

32 2-1 FFFF FFFF FFFF FFFE 1 0 0000 0001 0000 0000 2.4. ábra: A memória sematikus képe 5. A kontroll buszon jelzi a processzor, hogy véget ért az olvasás. Egy Pentium processzor olvasási ciklusa három órajel ciklusnak felel meg. Az első órajel ciklus alatt az 1. és 2. lépés hajtódik végre. A második órajel ciklus alatt a processzor várakozik. A harmadik órajel ciklus alatt az utolsó két lépés fut le. Ha a memóriának mégsem sikerül az olvasás, akkor ezt jelzi a processzornak ami egy újabb órajel ciklusig vár. 2.5.3 Olvasási ciklus 1. A processzor elhelyezi az írandó adat címét a cím buszon. 2. A processzor elhelyezi az adatot az adat buszra. 3. A kontroll buszon a processzor kiadja a memória írási jelet. 4. A processzor várakozik amíg az írás megtörténik. 5. A kontroll buszon jelezzük az írás végét. A Pentium processzor írási cíklusa is három órajel ciklust igényel. Az 1. és 3. lépés az első órajel alatt következik be. A 2. lépés csak a második órajel ciklus alatt történik. A második órajel ciklus végén jelzi az írás végét. 2.5.4 Memória típusok A memóriákat különböző kategóriákba lehet csoportosítani. Az egyik legfontosabb tulajdonsága a memóriáknak, hogy csak olvashatók vagy írhatók-olvashatók. Szintén fontos tulajdonság, hogy a memória minden részének elérése azonos időben lehetséges (random-access) vagy csak szekvenciálisan. A szekvenciális elérés magyarázatához a legjobb példa egy kazetta, amikor is addig kell olvasni a kazettát, amíg el nem értük a keresett adatot. Végül vannak a volatile memóriák, melyeknél amíg feszültség alatt van az egység csak addig őrzi meg a tartalmat. A nonvolatile memória akkor is megőrzi a tartalmát ha nincs feszültség alatt az egység. Csak olvasható memóriák A csak olvasható memóriák (Read Only Memory vagy ROM) csak olvasási műveletet enged. Ebbe a memóriába nem tudunk írni. A fő előnyük, hogy egyben nonvolatile memóriák is. A ROM memóriák 21

tartalmát a gyárban égetik bele. Ezeket a memóriákat olcsó gyártani. A régebbi számítógépekben a BIOS általában ROM. Vannak úgynevezett programozható ROM-ok is (PROM), illetve törölhető (erasbale) PROM-ok (EPROM). Írható-olvasható memóriák Az írható-olvasható memóriákat általában RAM-nak (random access memory-nak) is szokták nevezni, habár a ROM-ok esetén is igaz az, hogy minden része azonos időben érhető el. Ezeket a memóriákat két csoportba lehet sorolni: statikus és dinamikus. A statikus RAM memóriák (SRAM) megőrzi az adatot a beírás után, minden további menipuláció nélkül, amíg a rendszer feszültség alatt van. Ilyen memória a cache vagy a regiszterek. Ezzel szemben a fő memória dinamikus (DRAM). A DRAM egy komplex eszköz, mely kondenzátorok segítségével tárol egy bitet. A feltöltött kondenzátor jelöli az 1-es értéket. Mivel a kondenzátorok idővel vesztenek a töltésükből ezért időközönként frissíteni kell. Tipikusan 64 ms a frissítési periódus. Az olvasás során azt teszteljük, hogy a kondenzátor fel van-e töltve. Ugyanakkor ez a tesztelés tönkre is teszi a töltést. Ebben az értelemben a DRAM egy speciális memória, mivel az olvasás is destruktív, nem csak az írás. A legtöbb memória esetén csak az írás destruktív. A destruktív olvasás következménye, hogy az olvasás után egy helyreállítási ciklus szükséges. Ennek az a következménye, hogy az olvasás kétszer olyan sokáig tart mint más memóriák esetén. Modern memória típusok: FPM DRAM: Fast page-mode DRAM EDO DRAM: Extended Data Output DRAM SDRAM: synchronous DRAM DDR SDRAM RDRAM: Rambus DRAM 2.5.5 Byte sorozatok tárolása Természetesen általában nem csak egy byte-ot kell tárolni, hanem több byte-ot is. Például egy egész számot a C programozási nyelvben általában 4 byte-on tárolunk. Felmerülhet a kérdés, hogy hogyan tároljuk ezt a 4 byte-ot a memóriában? A 2.5. ábra két megoldást is mutat. Az ábrán az MSB jelölés a Most Significant Byte -nek felel meg, míg az LSB a Least Significant Byte. Mindkét megoldás esetén a 100-as címet adtuk meg, és ehhez képest történik a tárolás. A Little-endian tárolási módban a legkisebb helyiértékű byte (LSB) tárolódik először. Ezzel szemben a Big-endian tárolási módban a legnagyobb helyiértékű byte (MSB) tárolódik legelőször. Nézzünk egy másik példát a Little-endian tárolási módra. Az 1234h hexadecimális szám esetén először a 34h, majd a 12h byte-ot tárolja a rendszer. Az 12345678h szám esetén a tárolási sorrend: 78h, 56h, 34h, 12h. Melyik tárolási módszer a jobb? Mindkettő ugyanolyan jó. Csak a processzor tervező döntése, hogy melyiket használja. A Pentium processzorok a Little-endian tárolási módot használják. A MIPS és PowerPC processzorokon a Big-endian tárolási mód az alapértelmezett, de át lehet konfigurálni őket Little-endian tárolási módra is. Általában a különböző tárolási mód nem okoz problémát, ha mindig csak egyféle processzort használunk. Az igazi problémák akkor jelennek meg, ha különböző tárolási módszert használó processzorok között akarunk egy programot hordozni. Ebben az esetben az adatokat konvertálni kell! 22

MSB LSB 11110100 10011000 10110111 00001111 cím cím 11110100 10011000 10110111 00001111 103 103 102 102 101 101 100 100 00001111 10110111 10011000 11110100 Little-endian Big-endian 2.5. ábra: Little-endian és Big-endian tárolási mód 2.5.6 Adat alignment problema Egy program végrehajtási sebességét több tényező is befolyásolja. A tényezők közül néhány a programozó befolyása alatt van, míg másokat nem tudnak befolyásolni. Ebben a fejezetben az egyik fontos tényezőt vizsgáljuk meg. Tegyük fel, hogy egy 32 bites adatot szeretnénk olvasni a memóriából. Azt is tegyük fel, hogy az adat busz szintén 32 bites. Ha az olvasni kívánt adat címe néggyel osztható, akkor a memóriában pont úgy van elhelyezve, hogy egy sorba esik. Ez látható a 2.6. ábrán és ezt szoktuk illesztett, aligned adatnak nevezni. Mivel az adatbusz 32 bites, ezért egyszerre 4 byte-ot, egy sort lehet beolvasni a memóriából. Ez azt jelenti, hogy ha a cím nem osztható néggyel, akkor az adat két sorba kerül és kétszer kell olvasni a memóriából, majd ezekből fogja a processzor összeállítani a szükséges 32 bites adatot. A kétszeri olvasásnak hatása van a program futására, mivel a nem illesztett adatok miatt lassabban fog futni! n+3 k+2 24-31 16-23 n+2 k+1 8-15 n+1 k 0-7 n+0 k+3 CPU adatbusz 32 bit memória adat1 adat2 2.6. ábra: Adat illesztés - data alignment Az adat illesztés problémája teljesen transzparans módon, vagyis nem jelenik meg a felhasználó számára, kivéve, hogy a program lassabban fut. A 16 bites adatokat 2 byte-ra kell illeszteni. Ez azt 23

Cím busz Adat busz Kontroll busz Adat Státusz Parancs I/O kontroller I/O eszköz 2.7. ábra: Input/Output eszköz sematikus ábrája jelenti, hogy a cím legkisebb helyiértékű bite zérus, vagyis a cím páros. A 32 bites adatokat 4 byte-ra kell illeszteni vagyis a cím két legkisebb helyiértékű bite zérus. És így tovább. A Pentium processzorok megengedik az illesztett ( aligned ) és nem illesztett adattárolást is. Bizonyos processzorok az előbb leírt hatékonysági probléma miatt nem engedik meg, hogy az adat ne legyen illeszteve. 2.6 Input/Output Az Input/Output eszközök teszik lehetővé, hogy a számítógépek kommunikáljanak a külvilággal. Input/Output eszköz lehet hogy csak adatszolgáltatásra alkalmas, input-ra, például az egér, vagy csak output-ra képes, például a monitor, vagy input-ra és output-ra is képes. Így lényegében az I/O eszközöknek két fő célja van, a külvilággal kommunikálni és adatot tárolni. Mindegyik kommunikáció a rendszer buszon keresztül történik, bár az I/O eszközök nem közvetlenül kapcsolódnak a buszhoz, hanem van egy I/O kontroller az eszköz és a rendszer busz között, ahogy ez 2.7. ábrán látható. Két fontos ok miatt van szükség ezekre az I/O kontrollerekre: 1. A különböző I/O eszközöket különböző módon kell kezelni. Ez azt jelenti, hogy a különböző eszközökkel különböző módon kell kommunikálni, néha várni kell az adat megérkezésére vagy vezérlő jeleket kell adni. Ha a processzornak kellen mind ezt a feladatot ellátni, akkor több időt töltene ezzel, mint a felhasználó kiszolgálásával, vagyis a programok futtatásával. Az I/O eszköz kontroller elvégzi a processzor helyett ezeket a feladatokat. 2. A másik ok, hogy a rendszer buszon keresztül küldött elektromos jel igen alacsony, ami azt is jelenti, hogy a rendszer busz nem lehet túl hosszú. Emiatt az I/O eszköz kontrollerek közel vannak a processzorhoz, például a számítógép házban, és majd a kontroller tud külön, erősebb jelet küldeni az eszköznek. Az 2.7. ábra azt is mutatja, hogy az I/O eszköz kontrollerekben általában három regiszter is van. Például egy nyomtató esetén a Státusz regiszter jelzi, hogy az eszköz készen áll-e, az Adat regiszterbe kell tenni a nyomtatandó karaktert és a Parancs regiszterben kell utasítást adni az eszköznek, hogy nyomtassa ki a karaktert. A processzor I/O portokon keresztül éri el ezekete a regisztereket. Az I/O port nem más mint az I/O eszközön levő regiszter címe. Az I/O portok lehetnek a memóriára illesztettek, memory-mapped I/O. Ilyen rendszer például a MIPS processzorban van. A Pentium processzorok egy I/O cím tartományt használnak. Ez a cím tartomány különbözik a memória cím tartományától. Ebben az esetben külön I/O utasításokat kell használni. Ugyanakkor ez az utóbbi technika a memóriára illesztett I/O-t is lehető teszi. Később látni fogjuk, hogy például a képernyő a memóriára illeszthető és úgy is írhatunk a képernyőre, hogy egy speciális memória területre írunk. Ezzel szemben a billentyűzettel lehet I/O utasításokkal is kommunikálni. 24

2.6.1 I/O eszközök elérése Amikor assembly-ben programozunk közvetlenül vezérelhetjük az I/O eszközöket. Bár erre lehetőségünk van, de leírások és segítség nélkül gyakran nagyon bonyolult lehet, illetve minden esetben saját input és output függvényeket kellene kifejlesztenünk. Ezenkívül, ha mindenkinek teljesen szabad hozzáférése van az I/O eszközökhöz, akkor rosszindulatú emberek ezt ki is használhatják. Ezért van az, hogy általában az operációs rendszer kontrollálja az eszközökhöz való hozzáférést, illetve biztosítja a rutinokat is amiket használhatunk. A rutinok általában valamilyen megszakítást használnak. A megszakításokat a 8.2. bekezdésben tárgyaljuk. 2.7 Összefoglalás Ebben a fejezetben a számítógép alapvető elemeit ismertük meg olyan mélységben amire szükségünk lehet az assembly programozás során. Ezek az ismeretek lehetnek újak, illetve bizonyos fogalmak előfordulhattak más tárgyak keretében. 2.8 Ellenőrző kérdések 1. Milyen részekből áll egy sematikus számítógép? 2. Mi a fetch-decode-execute ciklus? Melyik lépésben, mi történik? 3. A rendszer busz milyen fő részekből áll? Melyiknek mi a szerepe? 4. Ha a processzornak 64 cím vonala van, mekkora lehet maximálisan a memória mérete? Mi az utolsó byte címe? 5. Mi határozza meg, hogy a memória és a processzor között adatok mérete mekkora? 6. Egy 2GH-es processzorban mekkora egy óra jel ciklus? 7. Miben különbözik a load/store architektúra a többi architektúrától? 8. Adjon magyarázatot arra hogy a RISC processzorokon az utasítások egymás utáni végrehajtása miért lehet gyorsabb mint a CISC processzorokon! 9. Mit jelent a három címes architektúra? 10. Miben különbözik a három és két címes architektúra? 11. Hogyan lehet olyan architektúrát megvalósítani, amelyikben az utasításoknak nem kell argumentumot megadni? 12. Adja meg a következő matematikai műveleteket pszeudo assembly-ben két címes architektúra esetén: E = A * B + C - D 13. A RISC vagy a CISC processzorokra jellemző a nagy számú regiszter? Melyik címzési architektúra esetén van szükség erre a nagyszámú regiszterre? 14. A Pentium processzor a RISC vagy CISC processzorok családjába tartozik? 15. A MIPS processzor a RISC vagy CISC processzorok családjába tartozik? 16. Hogyan lehet megvalósítani a feltételes ugró utasítást különböző architektúrákon? 17. Mi a PC regiszter szerepe a feltételes ugró utasítás végrehajtása során? 25

18. Hogyan néz ki a memória sematikus képe? Jelölje a minimum és maximum indexet 16 bites adatbusz esetén. 19. Mi jellemzi a ROM memóriákat? 20. Mi a különbség a statik és dinamikus RAM-ok között? 21. Mi a DRAM működésének alapelve? Miért dinamikus memória? 22. Miért kell frissíteni a DRAM memóriát? 23. Mi a különbség a volatile és nonvolatile memória között? 24. Mit jelent a little-endian tárolási mód? 25. Hogyan tárolódik a 44443333h hexadecimális szám a big-endian tárolási móddal? 26. Milyen tárolási módot használ a Pentium processzor? 27. Mit jelent az adat alignment? 28. Miért van hatással a nem illesztett adat tárolás a programok sebességére? 29. Miért van szükség I/O kontrollerre? 30. A processzor milyen módokon kommunikálhat az I/O kontrollerrel? 26

3. Fejezet A processzor Az Intel cég 1969-ben vezette be az első processzorát, a 4004 processzort. Ezt követte a 8080 és 8085 processzorok. Ezek a processzorok vezettek az Intel Architektúra (IA) kidolgozásához, a 8086- os processzorhoz, 1979-ben. A 8086 processzornak 20 bites cím busza és 16 bites adatbusza van. A következő generáció a 80186 processzor volt, melyben újabb utasításokat vezettek be, de a cím és adat busz mérete változatlan maradt. Mivel ezt a processzort nem igazán használták, így az igazi következő generációs processzor a 8086 után a 80286 processzor volt. A 80286 processzornak 24 bites cím busza van, amivel 16 MByte memóriát lehet megcímezni. Ugyanakkor az adatbusz megmaradt 16 bites. A másik újítás a védett mód (protected mode) bevezetése volt. Az Intel cég első igazi 32 bites processzora a 80386-os processzor volt, melynek 32 bites cím és adat busza van. Ezzel a processzorral 4GByte memóriát lehet megcímezni, ráadásul akár egyben, ami lehetővé tette a flat módot. A 80486 processzor 1989-ben jelent meg. A processzorba beépült a matematikai ko-processzor, egy 8KB-os L1-es cache is került a hardware-be, támogatta az L2 cache-t is és lehetővé vált a párhuzamos futtatás. A Pentium processzorok a legújabbak az Intel-től, bár itt a Pentium nevet mint a processzorok egy családjának a neveként használjuk. Az első Pentium processzort 1983-ban mutatták be. Azóta megjelentek a Pentium Pro, Pentium II, Pentium III és Pentium 4 processzorok. A processzorokról ad áttekintést a 3.1. táblázat. A hagyományos Intel architektúrától jelentősen eltér az Itanium processzor, mely RISC alapú, eltérően az Intel más processzoraitól, és más újításokat is tartalmaz. Ugyanakkor, ma (2009. szeptember) már kijelenthetjük, hogy ez a processzor nem váltotta be a hozzá fűzött reményeket és nem terjedt el olyan mértékben a számítógépes piacon, hogy jelentős szereplője legyen. Processzor Év Frekvencia Regiszter Adat busz Maximum (MHz) méret méret memória 8086 1979 8 16 16 1 MB 80286 1982 12.5 16 16 16 MB 80386 1985 20 32 32 4 GB 80486 1989 25 32 32 4 GB Pentium 1993 60 32 64 4 GB Pentium Pro 1995 200 32 64 64 GB Pentium II 1997 266 32 64 64 GB Pentium III 1999 500 32 64 64 GB Pentium 4 2000 1500 32 64 64 GB 3.1. tábla: Processzorok áttekintése 27