Inštrukcie presunov dát


<= =>


Každý program musí byť schopný presunov dát a to medzi registrami, registrami a pamäťou, registrami a vstupmi/výstupmi. Pri tejto operácii si musíme vždy uvedomiť, koľkobitové číslo presúvame. Počet bitov je väčšinou špecifikovaný menom použitého registra (osembitové - AH, AL, BH, BL, . . ., šestnásťbitové - AX, BX, BP, DI, ES, DS . . .). V prípade, že používame len pamäť, špecifikuje počet bitov pre operáciu označenie:

Presuny registre - register, register - pamäť

Všetky presuny tohoto typu prevedieme univerzálnou inštrukciou: Použitie tejto inštrukcie demonštruje príklad:

#include <stdio.h>
unsigned char slabika;   // v pamäti rezervuj 8 bitov a označ ich slabika
unsigned int slovo;      // v pamäti rezervuj 16 bitov a označ ich slovo
void main() {
  asm {
    MOV AL, 10           // do registra AL dosaď 8 bitov, hodnotu 10
    MOV slabika, AL      // do pamäti na miesto ozn. slabika dosaď obsah AL
    MOV BX, 10           // do registra BX (16 bitový) dosaď 10
    MOV slovo, BX        // do pamäti na miesto ozn. slovo dosaď 16 bitov bx
  }
  printf("%d %d", slabika, slovo);
}

Tento program má po preklade na miestach premenných v bloku asm označenie pamäťového miesta, ktoré pre ne bolo vyčlenené. Miesto pre premenné je vždy v segmentu globálnych premenných. Segmentová adresa tohoto bloku je vždy umiestnená v registri DS. To, že DS ukazuje na segment dát programu, môže viesť k chybe, ktorá spočíva v jeho zmene a následnom čítaní z globálnych premenných. Takže pozor! Po zmene registru DS je práca s globálnymi premennými nemožná, pretože sme si k nim odrezali cestu. Do segmentových registrov nejde dosadiť hodnota priamo. Tú najrýchlejšie dosadíme tak, že ju vložíme do niektorého univerzálneho registra a z neho potom do segmentového registra (napríklad MOV AX,adresa; MOV ES,AX).

Metódy adresovania

Miesto (offset) v pamäti označuje vždy určitá hodnota zapísaná v hranatých zátvorkách. Inštrukcia MOVBYTE PTR ES:[0x100F], 10 znamená: na adresu slabiky offset 100F (0x označuje použití hexadecimálnej sústavy) v segmente určenom adresou v ES, dosaď hodnotu 10. Ak segment nešpecifikujeme označením a dvojbodkou, vzťahuje sa adresa k segmentu v DS. V praxi by táto metóda obmedzovala programátora v rozlete. Preto ASM86 umožňuje i ďalšie metódy adresovania. Ale po poriadku . . .

Ich použitie umožní zistiť adresu deklarovaných premenných.

unsigned char premenna;
void main() {
  asm MOV BYTE PTR [offset premenna], 10
}

Segmentová adresa sa v tomto príklade nemusí určiť. Je v DS, a ten sa nemusí uvádzať. Prekladač C++ túto metódu používa i pre naše globálne premenné. Pri preklade je totiž každej premennej pridelené miesto v pamäti s pevnou offsetovou adresou (takže zápis OFFSET premenná nesie práve túto adresu). Špecifikácia, či sa jedná o slabiku, alebo slovo, je nutná, pretože inak by procesor nevedel, či má číslom obsadiť jednu, alebo dve slabiky.


unsigned char premenna;
void main() {
  asm {
    MOV BX, offset premenna  // do BX dosaď adresu premennej
    MOV BYTE PTR [BX], 10    // na jej adresu dosaď hodnotu 10
  }
}

unsigned char pole[10];
void main() {
  asm {
    MOV SI, 0                            // nuluj register SI
    MOV BYTE PTR [SI + offset pole], 10  // adr. pole sčítaj s SI a dosaď 10
  }
}

Program dosadí na prvé miesto pole hodnotu. Pretože register SI môžeme zvyšovať, budeme týmto spôsobom realizovať pohyb v poli.


unsigned char pole[10];
void main() {
  asm {
    MOV BX, offset pole        // do registra BX dosaď adresu poľa
    MOV SI, 0                  // do registra SI dosaď 0
    MOV BYTE PTR [BX][SI], 10  // na prvý prvok v poli ulož 10
  }
}

Prefix preskočenia

V assembleri mikroprocesoru 8086 sa objavuje i nový výraz. Prefix znamená určitú špecifikáciu pre nasledujúcu inštrukciu. Zatiaľ sme si ukázali, ako zmeniť špecifikáciu segmentového registra adresy s pomocou jeho označenia a dvojbodky. Ďalším spôsobom je použitie prefix zmeny segmentu: SEGDS, SEGES, SEGCS, SEGSS. Tieto označenia sú prefixami preskočenia (zmeny segmentu) pre jednotlivé segmentové registre. Napríklad: MOV AX, ES:[BX] je rovnaké, ako by sme použili SEGES MOV AX, [BX] (i keď zápis je rôzny, kód programu bude po preklade rovnaký).

Práca so zásobníkom

Zásobník je časť v pamäte počítača vyhradená na odkladanie dát. Je organizovaná tak, že dáta, ktoré sú uložené naposledy, vyberáme ako prvé. Na vrchol zásobníku ukazujú adresy uložené v registroch SS a SP (prípadne BP). Pridávaním dát do zásobníka sa offset v SP automaticky znižuje o dve (a naopak). Musíme si teda uvedomiť, že do zásobníka môžeme odkladať len šestnásťbitové dáta. Pre prácu so zásobníkom slúžia inštrukcie:

unsigned int premenna;
void main() {
  premenna=10;         // do pamäte na adresu premenné dosaď 10
  asm {
    MOV  AX, premenna  // obsah premennej dosaď do registra AX
    MOV  BX, 0xBBBB    // do registra BX dosaď číslo
    PUSH AX            // ulož obsah AX
    PUSH BX            // ulož obsah BX
    MOV  AX, 0xAAAA    // prepíš obsah AX
    MOV  BX, 0xCCCC    // prepíš obsah BX
    POP  BX            // obnov obsah BX
    POP  AX            // obnov obsah AX
    MOV  premenna, AX  // vráť obsah AX do premennej
  }
}

Tento program naznačuje postup ukladania a vyberania dát do a zo zásobníka. V zásobníku sú uložené i lokálne premenné procedúr a funkcií. Sú tu i parametre, ktorými je podprogram volaný. (Preto lokálne premenné NEMAJÚ segmentovú adresu v DS.) Občas potrebuje programátor uložiť register príznakov F, aby ho neskôr mohol obnoviť do pôvodného stavu. K tomu požívame inštrukciu PUSHF (pre uloženie) a POPF (pre obnovenie). Ak vo vkladanom assembleri chceme meniť niektorý zo "zakázaných" registrov (DS, BP), môžeme si jeho obsah uložiť do zásobníka. Podmienkou je ale to, že nezmeníme registre SS, SP. Tým by sme si podrezali vetvu pod sebou. Ďalšie možné použitie zásobníka je pri práci s časťou pamäti, v ktorej máme pole slov (šestnásťbitových dát). Nasmerovaním vrcholu zásobníka (SS:SP) na koniec tohoto poľa môžeme inštrukciami PUSH a POP s týmto poľom pracovať. Pritom sa bude automaticky zvyšovať a znižovať adresa. Pozor ale, obsahy SS a SP je nutné zase uschovať, najlepšie do pamäte na miesta premenných. V tom prípade ale nemôžeme meniť register DS (ES).

Presuny vstup-výstup - register

Každý sa niekedy pokúsime zapísať na port a čítať z neho. Je dobré si uvedomiť, že môžeme zapisovať osem i šestnásť bitov. Každý port, rovnako ako slabika v pamäti, má svoju adresu. Pri zápise šestnástich bitov zapisujeme teda i na port s adresou o jednu vyššiu. Prácu s portami prevedieme inštrukciami: Dáta sa čítajú, alebo zapisujú z (do) registra AL (osembitový prístup), AX (šestnásťbitový prístup). Adresu portu špecifikuje buď priamo adresa (IN AL, 0x0F) pri adrese osembitovej (spodných 256 portov), alebo register DX, v ktorom je šestnásťbitová adresa (MOV DX, 0xF10; OUT DX, AL).

Ďalšie presuny

Medzi presuny dát patrí aj:


<= =>