Instrukce přesunů dat
Každý program musí být schopen
přesunů dat a to mezi registry, registry a pamětí, registry a
vstupy/výstupy. Při této operaci si musíme vždy uvědomit,
kolikabitové číslo přesouváme. Počet bitů je většinou
specifikován jménem použitého registru (osmibitové - AH, AL,
BH, BL, . . ., šestnáctibitové - AX, BX, BP, DI, ES, DS . .
.). V případě, že používáme jen paměť, specifikuje
počet bitů pro operaci označení:
- BYTE PTR
označení pam. místa - specifikuje slabiku
- WORD PTR
označení pam. místa - specifikuje slovo
Přesuny
registr - registr, registr - paměť
Všechny přesuny tohoto typu
provedeme univerzální instrukcí:
- MOV cíl,
zdroj - do cíle přesuň ze zdroje (registr - registr,
registr - paměť, registr - hodnota, paměť - hodnota,
seg. registr - registr, seg.registr - paměť)
Použití této instrukce
demonstruje příklad:
uses crt;
var slovo:word; {v paměti rezervuj 16 bitů a označ je slovo}
slabika:byte; {v paměti rezervuj 8 bitů a označ je slabika}
begin
asm
MOV AL,10 {do registru AL dosaď 8 bitů, hodnotu 10}
MOV slabika,AL {do paměti na místo ozn. slabika dosaď obsah AL}
MOV BX,10 {do registru BX (16 bitový) dosaď 10}
MOV slovo, BX {do paměti na místo ozn. slovo dosaď 16 bitů BX}
end;
writeln (slabika,' ',slovo);
readkey;
end.
Tento program má po překladu na
místech proměnných v bloku asm označení paměťového
místa, které pro ně bylo vyčleněno. Místo pro proměnné je
vždy v segmentu globálních proměnných. Segmentová adresa
tohoto bloku je vždy umístěna v registru DS. To, že DS
ukazuje na segment dat programu, může vést k chybě, která
spočívá v jeho změně a následném čtení z globálních
proměnných. Takže pozor! Po změně registru DS je práce s
globálními proměnnými nemožná, protože jsme si k nim
uřízli cestu. Do segmentových registrů nejde dosadit hodnota
přímo. Tu nejrychleji dosadíme tak, že ji vložíme do
některého univerzáního registru a z něj teprve do
segmentového registru (například MOV
AX,adresa; MOV ES,AX).
Metody adresace
Místo (offset) v paměti
označuje vždy určitá hodnota zapsaná v hranatých
závorkách. Instrukce MOV BYTE PTR ES:[$100F], 10
znamená: na adresu slabiky offset 100F ($ označuje použití
hexadecimální soustavy) v segmentu určeném adresou v ES,
dosaď hodnotu 10. Jestliže segment nespecifikujeme označením
a dvojtečkou, vztahuje se adresa k segmentu v DS. V praxi by
tato metoda omezovala programátora v rozletu. Proto ASM86
umožňuje i další metody adresace. Ale popořadě . . .
- Přímá adresa
MOV AH, ES:[$1A40] - do registru AH
předej 8 bitů z adresy určené ES a číslem
Tuto metodu použijeme, jestliže předem víme adresu
hledaného místa v paměti. Na pomoc v Turbo Pascalu
jsou operátory:
- OFFSET
proměnná - vrací offsetovou adresu proměnné
- SEG
proměnná - vrací segmentovou adresu proměnné
(pro globální proměnné vrací vždy obsah DS)
Jejich použití umožní
zjistit adresu proměnných deklarovaných v části var
(const . . .).
Příklad:
var promenna: byte;
begin
asm
MOV BYTE PTR [offset promenna], 10 {na adresu slabiky proměnné dosaď 10}
end;
end.
Segmentová adresa se v
tomto příkladu nemusí určit. Je v DS, a ten se
nemusí uvádět. Překladač Pascalu tuto metodu
používá i pro naše globální proměnné. Při
překladu je totiž každé proměnné přiděleno místo
v paměti s pevnou offsetovou adresou (takže zápis OFFSET
proměnná nese právě tuto adresu). Specifikace, jestli
se jedná o slabiku, nebo slovo, je nutná, protože
jinak by procesor nevěděl, jestli má číslem obsadit
jednu, nebo dvě slabiky.
- Nepřímá adresa
MOV AH, ES:[BX] - do registru AH předej obsah
pam. místa specifikovaného adresou v BX
Pozor! Do registru AH je uložen obsah v paměti na
adrese v BX, ne obsah registru BX. Offsetová část
adresy je uložena v některém z adresových registrů
BX, BP, SP, SI, DI. Vzhledem k tomu, že obsah těchto
registrů můžeme měnit, použijeme tuto metodu v
případě pohybu po paměti.
Příklad:
var promenna: byte;
begin
asm
MOV BX, offset promenna {do BX dosaď adresu proměnné}
MOV BYTE PTR [BX], 10 {na její adresu dosaď hodnotu 10}
end;
end.
- Bázová adresa
MOV AH, [BX + adresa] - k registru BX přičti
konstantu adresa, výsledná hodnota je adresou odkud se
má načíst do registru AH
Bázová adresa se tvoří s pomocí obsahu jednoho z
bázových registrů BP, BX. Výraz v závorce se
vyhodnotí, přitom označení registrů zastupuje jejich
obsahy. Tento druh adresy používáme při
zjišťování hodnot parametrů určených pro
podprogramy (případně k přístupu k lokálním
proměnným).
- Indexovaná adresa
MOV AH, ES:[adresa + SI] <=> (je shodné) MOV
AH, adresa[SI] - registr SI sečti s konstantou adresa,
výsledek je hodnota adresy offsetu do paměti
Tento způsob adresace je obdobou předchozí tvorby
adresy. Používá se však při práci s bloky v
paměti. Zde jsou k dispozici indexové registry SI, DI.
Příklad:
var pole: array [0..9] of byte;
begin
asm
MOV SI, 0 {nuluj registr SI}
MOV BYTE PTR offset pole[SI], 10{adr. pole sečti s SI a dosaď 10}
end;
end.
Program
dosadí na první místo pole hodnotu. Protože registr
SI můžeme zvyšovat, budeme tímto způsobem realizovat
pohyb v poli.
- Kombinovaná adresa
báze + index
MOV AH, [BX + SI] <=> MOV
AH, [BX][SI] - obsahy registrů BX a SI sečti, výsledek
je hodnota offsetu odkud se má číst
Kombinovaná adresa umožňuje pracovat s adresou, která
se skládá ze součtu dvou registrů (jednoho bázového
BX, BP a jednoho indexového SI, DI).
Příklad:
var pole: array [0..9] of byte;
begin
asm
MOV BX, offset pole {do registru BX dosaď adresu pole}
MOV SI, 0 {do registru SI dosaď 0}
MOV BYTE PTR [BX][SI], 10 {na první prvek v poli ulož 10}
end;
end.
- Kombinovaná adresa
přímá + báze + index
MOV AH, [adresa + BX + SI] <=> MOV
AH, adresa[BX][SI] - sečti registry BX, SI a přičti
hodnotu adresa, výsledek je hodnota offsetu
Tuto adresaci použijeme například při práci s
hlavičkovými soubory. Bázový registr nastavíme na
počátek bloku paměti vyčleněného k uložení
souboru. Indexový registr vynulujeme. Konstantní
hodnota (adresa) může být rovna délce hlavičky.
Zvyšováním hodnoty v indexovém registru se pohybujeme
v datech hlavičkového souboru. Další možné
použití této adresace je při pohybu v
dvourozměrných polích. Hodnoty v obou registrech jsou
indexy pole. Konstantní adresa je adresou počátku
pole.
Prefix přeskočení
V assembleru mikroprocesoru 8086
se objevuje i nový výraz. Prefix znamená určitou specifikaci
pro následující instrukci. Zatím jsme si ukázali, jak
změnit specifikaci segmentového registru adresy s pomocí jeho
označení a dvojtečky. Dalším způsobem je použití prefixu
změny segmentu: SEGDS, SEGES, SEGCS,
SEGSS. Tato označení jsou prefixy
přeskočení (změny segmentu) pro jednotlivé segmentové
registry. Například: MOV AX, ES:[BX] je
stejné, jako bychom použili SEGES MOV
AX, [BX] (i když zápis je různý, kód programu bude po
překladu stejný).
Práce se zásobníkem
Zásobník je část v paměti
počítače vyhrazená k odkládání dat. Je organizovaná tak,
že data, která jsou uložena naposledy, vyjímáme jako první.
Na vrchol zásobníku ukazují adresy uložené v registrech SS a
SP (případně BP). Přidáváním dat do zásobníku se offset
v SP automaticky snižuje o dvě (a naopak). Musíme si tedy
uvědomit, že do zásobníku můžeme odkládat jen
šestnáctibitová data. Pro práci se zásobníkem slouží
instrukce:
- PUSH zdroj -
do zásobníku ulož obsah zdroje (registr, paměť,
[286] hodnota)
- POP cíl -
ze zásobníku dosaď do cíle (registr, paměť)
- PUSHA -
[286] do zásobníku ulož postupně registry AX, CX, DX,
BX, SP, BP, SI, DI
- POPA - [286]
ze zásobníku dosaď zpět registry uložené instrukcí
PUSHA
- PUSHF - do
zásobníku ulož obsah registru F v šestnáctibitovém
tvaru
- POPF -
hodnotou ze zásobníku obsaď registr F
Příklad:
var promenna:word;
begin
promenna:=10; {do paměti na adresu proměnné dosaď 10}
asm
MOV AX, promenna {obsah proměnné dosaď do registru AX}
MOV BX,$BBBB {do regisru BX dosaď číslo}
PUSH AX {ulož obsah AX}
PUSH BX {ulož obsah BX}
MOV AX,$AAAA {přepiš obsah AX}
MOV BX,$CCCC {přepiš obsah BX}
POP BX {obnov obsah BX}
POP AX {obnov obsah AX}
MOV promenna, AX {vrať obsah AX do proměnné}
end;
end.
Tento program naznačuje postup
ukládání a vybírání dat do a ze zásobníku. V zásobníku
jsou uloženy i lokální proměnné procedur a funkcí. Jsou zde
i parametry, kterými je podprogram volaný. (Proto lokální
proměnné NEMAJÍ segmentovou adresu v DS.) Občas potřebuje
programátor uložit registr příznaků F, aby ho později mohl
obnovit do původního stavu. K tomu požíváme instrukci PUSHF
(pro uložení) a POPF (pro obnovení).
Jestliže ve vkládaném assembleru chceme měnit některý ze
"zakázaných" registrů (DS, BP), můžeme si jeho
obsah uložit do zásobníku. Podmínkou je ale to, že
nezměníme registry SS, SP. Tím bychom si podřízli větev pod
sebou. Další možné použití zásobníku je při práci s
částí pamětí, ve které máme pole slov
(šestnáctibitových dat). Nasměrováním vrcholu zásobníku
(SS:SP) na konec tohoto pole můžeme instrukcemi PUSH
a POP s tímto polem pracovat. Přitom se bude
automaticky zvyšovat a snižovat adresa. Pozor ale, obsahy SS a
SP je nutné zase uschovat, nejlépe do paměti na místa
proměnných. V tom případě ale nemůžeme měnit registr DS
(ES).
Přesuny
vstup-výstup - registr
Každý se někdy pokusíme zapsat
na port a číst z něj. Je dobré si uvědomit, že můžeme
zapisovat osm i šestnáct bitů. Každý port, stejně jako
slabika v paměti, má svojí adresu. Při zápisu šestnácti
bitů zapisujeme tedy i na port s adresou o jednu vyšší.
Práci s porty provedeme instrukcemi:
- OUT adresa
portu, zdroj - pro zápis na port (AL, AX-> port)
- IN cíl,
adresa portu - pro čtení z portu (port-> AL, AX)
Data se čtou, nebo zapisují z
(do) registru AL (osmibitový přístup), AX (šestnáctibitový
přístup). Adresu portu specifikuje buď přímo adresa (IN
AL, $0F) při adrese osmibitové (spodních 256 portů), nebo
registr DX, ve kterém je šestnáctibitová adresa (MOV
DX, $F10; OUT DX, AL).
Další přesuny
Mezi přesuny dat patří i:
- XCHG cíl,
zdroj - vzájemná výměna hodnot zdroje a cíle
(paměť - registr, registr - registr)
- LAHF - do
registru AH dosaď nižší slabiku registru příznaků
F
- SAHF - z
registru AH dosaď do nižší slabiky registru
příznaků F
- XLAT - do AL
dosaď obsah slabiky v paměti s adresou v DS:[BX + AL]
(práce s tabulkou) a některé řetězcové instrukce o
kterých bude řeč později.
|