|  | 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] 
  
  
: 
          2115