kategória | ||||||||||
|
||||||||||
|
||
Az Assemly programozás alapjai: a 80*86 processzor regiszterei, címzési módok, PC megszakítások, a hadver programozás szintjei
A Assembly programozási nyelv az egyik
legrégebbi programozási nyelv, közvetlenül a gépi kódú programoz 141i87b ás után jelent
meg. Létjogosultságát bizonyítja, hogy speciális problémák megoldására még ma
is alkalmazzák. Manapság a hardverközeli programok készítésének leghatékonyabb
programozási nyelve. Az Assembly programok utasításai, szerkezete a gép
logikához igazodik. Az Assembly programok nagyon gyors, és hatékony programok,
mivel a processzor lehetõségeit maradéktalanul képesek kihasználni.
Az Assembly nyelvet háromféle módszerrel tudjuk felhasználni:
- Magasszintû programozási nyelvek programjainak forráskódjába Assembly
nyelvû utasításokat ágyazunk.
- Tárgykód szintjén szerkesztjük be a magasszintû programba (Pascal
esetén $L direktíva)
- "Valódi" Assembly programokat írunk.
Több magasszintû programozási nyelv támogatja az Assembly programrészletek beillesztését, Turbo Pascal, Borland C, stb.
A hardver programozás szintjei:
A hardver egységeket programjaink írása során többféleképpen kezelhetjük. A hardver programozása során négy szintet kell elkülönítenünk:
Magasszintû
programozási nyelv utasításaival:
A legkevésbé hatékony, de a programozó szempontjából a legkényelmesebb eljárás,
amikor az adott programozási nyelv utasításainak segítségével kezeli a harver
egységeket. Pld.:
Writeln('Pascal');
DOS (operációs renszer
szintû) megszakítás használatával:
Az operációs rendszer szintjén definiált rutin, amely a hardver egységeket,
erõforrásokat kezeli. A DOS (Windows 9x) operációs rendszerek esetében
ez a 21h sorszámú megszakítás, amelynek a 2h alfunkciója kezeli a képernyõt.
A megszakítás segítségével egy karaktert tudunk a kurzor pozíciójába kiírni. A
szükséges programrészlet:
Uses DOS;
Var R: Registers;
Begin
...
R.AH:= 2;
R.AL:= ord('P');
Intr($21, R);
R.AH:= 2;
R.AL:= ord('A');
Intr($21, R);
R.AH:= 2;
R.AL:= ord('S');
Intr($21, R);
...
End.
BIOS megszakítás
használatával:
A BIOS is definiálja a standard perifériák kezeléséhez szükséges
megszakításokat. A BIOS megszakítások a 10h sorszámot kapták, a 14 alfunció
segítégével egy karaktert írhatunk ki a képernyõre a kurzor pozíciójába.
A szükséges programrészlet:
Uses DOS;
Var R: Registers;
Begin
...
R.AH:= 14;
R.AL:= ord('P');
Intr($10, R);
R.AH:= 14;
R.AL:= ord('A');
Intr($10, R);
R.AH:= 14;
R.AL:= ord('S');
Intr($10, R);
...
End.
Közvetlen hardverhozzáférés használatával:
Uses CRT;
Var Kep: Array [1..25, 1..80, 1..2] of byte absolute $B800:$0000;
Begin
ClrScr;
Kep[1][1][1]:= Ord('P');
Kep[1][2][1]:= Ord('a');
Kep[1][3][1]:= Ord('s');
Kep[1][4][1]:= Ord('c');
Kep[1][5][1]:= Ord('a');
Kep[1][6][1]:= Ord('l');
End.
A programban a képernyõ memória
felépítésének megfelelõ tömböt deklaráltunk, majd az absolute direktíva
segítségével a változót rádefiniáltuk a képernyõmemória
kezdõcímére (B800h:0000h). Ezután már csak a tömb elemeinek kell értéket
adnunk, így közvetlenül írhatunk a szöveges képernyõ memóriájába.
Mielõtt a szöveget kiírnánk a képernyõre, célszerû végrehajtani
egy képernyõtörlést, így szebb lesz...
A 80x86 processzor regiszterei:
Az Assembly programok írása során közvetlenül a processzornak adjuk az utasításokat, a processzor (illetve az operációs rendszer) által definiált rutinokat - a megszakításokat - használjuk fel a program írása során. A megszakítások használatához a processzor belsõ tárolóhelyeit, a regisztereket kell felhasználnunk.
A regisztereket a feladatuk alapján csoportosíthatjuk:
Általános
regiszterek:
AX: Akkumlátor regiszter, osztásnál és szorzásnál van kitüntetett szerepe.
BX: Bázis regiszter, indirekt és bázisregiszteres indirekt címzés során kap
szerepet.
CX: Számlálóregiszter, ciklusszervezés és stringmûveletek esetén
alkalmazzuk.
DX: Adatregiszter, szorzás, osztás és I/O utasítások során fontos.
Vezérlõ
regiszterek:
IP: Utasításmutató. Automatikusan a következõ utasítás címét
tartalmazza. Ugrások során fontos.
SP: Veremmutató. Automatikusan kap értéket, program hívásakor kap szerepet.
BP: Báziscím mutató. A Stack szegmens indirekt és bázisregiszteres címzésénél
használjuk.
SI: Forrás index. Stringmûveletek során használjuk.
DI: Célindex. Stringmûveletek során használjuk.
Flags: Státusz regiszter, hiba esetén használható.
Szegmens
regiszterek:
CS: Kódszegmens.
DS: Adatszegmens.
SS: Veremszegmens.
ES: Másodlagos adatszegmens.
FS: Másodlagos adatszegmens.
GS: Másodlagos adatszegmens.
A másodlagos adatszegmens regisztereket virtuális címzések során használjuk. A szegmensregiszterek közvetlenül nem kaphatnak értéket, csak egy másik regiszter tartalmát tölthetjük ide.
A megszakítások:
A megszakítások az operációs rendszer és a
BIOS által elõre definiált rutinok, amelyeket a programozó felszanálhat
a kívánt tevékenység elvégzéséhez.
A megszakítások használatához a regisztereket kell alkalmaznunk. Mivel a
processzor közvetenül hajtja végre az utasításokat, a megszakítások adatait
(I/O adatok) a regiszterekbe kell tölteni a megszakítás meghívása elõtt.
A megszakítások a számítógép perifériáinak, erõforrásainak alacsony szintû
kezelését hivatottak biztosítani. A különféle egységek kezeléséhez használható
megszakítások hexadecimális sorszámokat kapnak, amelyek segítségével az adott
megszakítás meghívható. A megszakításoknak általában vannak alfunkciói is.
Tehát mielõtt egy megszakítást használnánk a regisztereket fel kell
tölteni a szükséges értékekkel: megszakítás száma, alfunció száma, input
adatok. A megszakítás végrehajtása után szintén a regiszterek tartalmazzák a
kimeneti információkat, a regiszterek tartalmát kell menteni, ha szeretnénk a
késõbbiekben használni az output adatokat.
Néhány fontosabb megszakítás:
Képernyõ
kezelése: 10h megszakítás. (AX)
Képernyõtörlés: 0h alfunkció (AH)
Bemeneti információk:
Karaterfelbontás: 1- 40x25
színes (AL)
3- 80x25 színes (AL)
Kurzor beállítása: 1h
alfunkció (AH)
Bemeneti információk:
Kezdõsor (CH)
Zárósor (CL)
Karakter kiírása a kurzor
pozíciójába: 9h alfunkció
Bemeneti információk:
Karakter kódja (AL)
Képernyõ oldal (BH)
Attribútum (szín, háttér) (BL)
Ismétlésszám (CX)
Billentyûzet
kezelése: 16h megszakítás (AX)
Karakter olvasása: 0h alfunkció (AH)
Kimeneti információk:
Scan kód (AH)
Karakter kód (AL)
A
címzési módok:
Az Assembly programokból mind az adatterületet
(adatszegmenst) mind a kódterületet (kódszegmenst) tudjuk címezni. A kódterület
címzése tulajdonképpen a programban végrehajtott ugrást jelent, azon a címen
fog folytatódni a program végrehajtása, amely címre ugrunk.
A kódterület címzése:
Az ugrás lehet feltétel nélküli, illetve feltételes ugrás. A feltétel nélküli ugrás során a jmp utasítást használjuk. A feltétel nélküli ugrás fajtái:
IP
relatív címzés:
Az utasításban talált adatot hozzáadja az IP regiszter által tárolt értékhez,
itt folytatódik a program végrehajtása.
Pld: jmp vissza
Direkt
címzés:
Valamely regiszter tartalmazza a célcímet, a regiszter tartalmát használjuk fel
az ugrás során.
Pld: jmp bx
Indirekt
címzés:
A regiszter címén van a kívát cím.
Pld: jmp [bx]
A feltételes ugrás során csak akkor történik
meg a vezérlésátadás, ha a megfogalmazott feltétel teljesül. A feltételes ugrás
során a jmp utasítás feltételes változatait használjuk fel a kritériumok
meghatározásához. A feltételt az F (Flags) regiszter tartalmazza, az F
regiszter feltöltéséhez célszerû felhasználni a cmp utasítást. Példa: ha
ax regiszter értéke 5, akkor ugorjunk a vissza címkére:
cmp ax,5
je vissza
Tehát a feltételes ugrások két utasításból épülnek fel, az elsõ utasítás során megfogalmazzuk a feltételt, a második utasítás során pedig megvizsgáljuk az értékét, és ennek megfelelõ ugrást hajtunk végre.
A jmp utasítás feltételes változatai:
JA címke: op1op2
JNA címke: op1<=op2
JAE címke: op1=op2
JNC címke: op1=op2
JB címke: op1<op2
JC címke: op1<op2
JNE címke: op1<op2
...
Tehát a feltételes ugró utasítások variálható utasítások. Az elsõ
betû kötelezõen a J, a második és harmadik betû a feltételt
fogalmazza meg.
Tehát: JNE címke
J- Jump (ugrás)
N- Not (tagadás)
E- Equal (egyenlõ)
A variációhoz felhasználható karakterek és
jelentésük:
N: Not (tagadás)
L: Less (kevesebb)
G: Greater (több)
A: Above (felett)
B: Bottom (alatt)
C: Carry
Z: Zero (nulla)
E: Equal (egyenlõ)
Nyilván az egymást kizáró karakterkombinációk
nincsenek megengedve. Rossz példa: JAB címke.
Ciklusok az Assembly programban:
A ciklusok képzési is a feltételes ugrások felhasználásával történhet. Pld:
mov ax,1
@vissza: add ax,1
add bx,ax
cmp ax,5
jne vissza
A ciklusok szervezésekor van azonban egy kényelmesebb lehetõségünk is. A ciklusfeltétel vizsgálatához felhasználhatjuk a CX (utasításszámláló) regisztert. A CX regiszter használata esetén mindössze arra kell figyelni, hogy ennek a regiszterenek a tartalmát a ciklusmagban ne módosítsuk. A ciklus elkezdése elõtt a CX regiszterbe kell tölteni (mov cx, ...) a ciklus ismétléseinek számát, és a ciklusmag végét a LOOP címke utasítással kell zárnunk. Az elõbbi ciklus ilyen módon:
mov cx,5
mov ax,1
@vissza: add ax,1
add bx,ax
loop vissza
Az adatterület címzése:
Az adatterület címzése során tulajdonképpen a
direkt memóriakezelést valósítjuk meg. Az adatterületen tárolt változókhoz
közvetlen módon férhetünk hozzá, értéküket közvetlenül módosíthatjuk.
Az adatterület címzésének lehetõségei:
Kódba
épített adattal (közvetlen címzés):
A kívánt memóriacímet konstans értékként adjuk meg.
Pld: mov ax, $B800
Regiszteres
címzés:
A kívánt memóriacímet egy regiszter tartalmazza. Figyelni kell arra, hogy a
regiszterek azonos típusúak legyenek.
Pld: mov ax, bx
Közvetlen
memória címzés:
A második operandus egy változó, illetve egy változó címe.
Pld: mov ax, adat
Indexelt
címzés:
Pld: mov ax, [di+4]
Regiszter
indexelt címzés:
A kívánt memóriacím offset részét a BX, SI, DI regiszterek egyike tartalmazza.
Pld: mov ax, CS:[DI]
Bázis
relatív címzés:
A memóriacím a BX tartalmához viszonyított cím.
Pld: mov ax, [bx+4]
Bázis
indexelt címzés:
Pld: mov ax, [bx][si+10]
:
1979