Učebnice Assembleru 86

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.
Směr