Učebnice Assembleru 86

Aritmetické instrukce

Programátor při své činnosti potřebuje nejen přesuny dat. V každém programu jsou nutné i výpočty a to s běžnými daty, nebo s adresami. Ty se v assembleru provádějí jen s celými čísly. Operace s desetinnými čísly jsou zdlouhavé, i když jsou proveditelné pomocí určitých algoritmů. ASM86 pro ně ale nemá instrukce. Většina matematických operací se provádí s čísly v registrech nebo v paměti. Označení operandů je shodné jako při přesunech. Zároveň tyto instrukce nastavují indikátory registru F. Umožní tak větvit program. Informace o nastavovaných indikátorech najdeme v tabulce instrukcí (+).

Sčítání

Při tvorbě programu si musíme ujasnit, jestli chceme k cílovému místu přičíst 1, nebo jiné číslo. Podle toho volíme instrukci:

  • INC cíl - k cíli přičti jedna (registr, paměť)
  • ADD cíl, zdroj - k cíli přičti zdroj (registr - hodnota, paměť -hodnota, registr - registr, paměť - registr, registr - paměť)
  • ADC cíl, zdroj - stejně jako ADD, ale přičti i bit CF (přenos)

Příklady:

INC AX - přičti k registru AX hodnotu 1
INC WORD PTR [BX] - přičti k slovu na adrese určené DS:BX hodnotu 1
INC BYTE PTR CS:[adresa] - přičti k slabice na adrese určené CS:adresa (konstantní) 1
SEGES INC BYTE [DI + 2] - přičti k slabice na adrese ES:DI + 2 hodnotu 1
ADD AX, BX - ke slovu v registru AX přičti obsah registru BX (slovo)
ADD AH, 8 - k slabice v registru AH přičti číslo 8}
SEGCS ADD DX, WORD PTR [BX] - k registru DX přičti slovo na adrese CS:BX
ADD promenna, 5 - k deklarované proměnné přičti 5
ADD BYTE PTR [SI], 30 - k slabice na adrese DS:SI přičti 30}
ADD BYTE PTR ES:[BP], AL - k slabice na adrese ES:BP přičti obsah registru AL

Pokud při těchto operacích dojde k přeplnění cíle, nastaví se registr OF do log. 1. Aby při odlaďování vašich programů nedošlo ke zbytečným hádkám s překladačem, uvědomte si, že zdroj i cíl musí mít stejný počet bitů (tzn. 8, nebo 16).

Odčítání

Instrukce sloužící k odčítání jsou zápisem operandů shodné s instrukcemi pro sčítání. Proto si uvedeme jen jejich seznam:

  • DEC cíl - d cíle odečti 1 (registr, paměť)
  • SUB cíl, zdroj - od cíle odečti zdroj (registr - hodnota, paměť - hodnota, registr - registr, paměť - registr, registr - paměť)
  • SBB cíl, zdroj - stejně jako SUB, ale odečti i bit CF Příklady by byly shodné se sčítáním.

Přesto jsou zde specifické instrukce:

  • NEG cíl - otoč znaménko v cíli (registr, paměť)
  • CMP cíl, zdroj - odečti bez změny cíle, nastav jen registr F (registr - hodnota, paměť - hodnota, registr - registr, paměť - registr, registr - paměť)

Instrukce CMP porovnává dvě čísla odečtením. Protože ale nedojde k jejich změně, použijeme tuto instrukci před větvením programu. Za CMP totiž většinou následu+jí instrukce skoku závislé na stavu příznaků registru F.

Příklad:

uses crt;
var a,b,s,r:integer;
begin
 clrscr;      {vymaž obrazovku}
 write ('a=');
 readln(a);   {vstup hodnoty a}
 write ('b=');
 readln(b);   {vstup hodnoty b}
 asm          {začátek bloku asm}
  MOV AX, a   {do AX vlož hodnotu proměnné a (z paměti)}
  ADD AX,b    {k AX přičti hodnotu proměnné b}
  MOV s, AX   {do proměnné s vlož součet z registru AX}
  MOV AX,a    {znovu naber a}
  SUB AX,b    {odečti od AX hodnotu b}
  MOV r,AX    {do proměnné r vlož rozdíl z registru AX}
  INC a       {k a přičti 1}
  DEC b       {od b odečti 1}
 end;         {konec bloku asm}
 writeln ('a+b=',s,' a-b=',r);{vypiš obsahy proměnných}
 writeln ('a+1=',a,' b-1=',b);
end.

Uvedený příklad ukazuje nejjednodušší použití instrukcí ADD, SUB, INC, DEC. Všimněte si, že se zápisy adres proměnných si nemusí programátor ani moc lámat hlavu. V tom mu totiž pomáhá překladač Pascalu.

Násobení

I když programátoři neradi používají instrukce násobení a dělení pro jejich dlouhou dobu provádění (na procesoru 8086, u jiných procesorů je už rychlé), ASM86 je má. Někdy dokonce neexistuje jiná možnost než je použít. I tyto operace jsou definovány jen na celých číslech. Rozlišujeme také, jestli je provádíme se znaménkem, nebo bez znaménka.

  • MUL zdroj - registr AL vynásob se zdrojem (osmibitový registr, nebo paměť) a výsledek zapiš do registru AX (osmibitové násobení).
  • MUL zdroj - registr AX vynásob se zdrojem (šestnáctibitový registr, nebo paměť) a výsledek (32 bitů) zapiš do registrového páru DX,AX za sebou (šestnáctibitové násobení).
  • IMUL zdroj - jako MUL ale násobení se znaménkem IMUL cíl,[zdroj,]konstanta - [286], do cíle vlož součin zdroje a konstanty (šestnáctibitový registr - šestnáctibitový registr - hodnota, šestnáctibitový registr - slovo v paměti - hodnota, šestnáctibitový registr - osmibitová hodnota, to znamená cíl := zdroj * konstanta, nebo cíl := cíl * konstanta)

POZOR!, o kolikabitové násobení se jedná určuje označení místa zdroje.

Dělení

Tato operace je jednou z nejzdlouhavějších. Její provádění trvá (na 8086) až 190 period hodin (sčítání trvá kolem 3 period). Jeho výhodou je ale to, že je možné zjistit jak výsledek po celočíselném dělení (DIV), tak i zbytek po celočíselném dělení (MOD). A to všechno jen jednou instrukcí.

  • DIV zdroj - registr AX vyděl zdrojem (osmibitový registr, nebo paměť) a podíl ulož do AL, zbytek po dělení ulož do AH (Osmibitové dělení)
  • DIV zdroj - dvojslovo v registrech DX, AX vyděl zdrojem (šestnáctibitový registr, nebo paměť) a podíl ulož do AX, zbytek po dělení ulož do DX (Šestnáctibitové dělení)
  • IDIV zdroj - jako DIV ale dělení se znaménkem Použití těchto instrukcí je podobné jako násobení. Program si musíme ošetřit tak, aby nemohlo dojít k dělení nulou. Jestliže k němu přesto dojde, procesor zavolá přerušení INT 0.

Příklad:

uses crt;
var a,b,d,z:byte;
          s:word;
begin
 clrscr;
 write ('a=');
 readln (a);
 write ('b=');
 readln (b);
 asm
  MOV AL,a {do AL vlož hodnotu a}
  MUL b    {vynásob hodnotou b (v paměti)}
  MOV s,AX {do proměnné s vlož součin z registru AX}
  MOV AH,0 {nuluj AH (číslo je jen 8 bitové)}
  MOV AL,a {do AL vlož hodnotu a}
  DIV b    {vyděl proměnnou b}
  MOV d,AL {výsledek vlož do proměnné d}
  MOV z,AH {zbytek po dělení vlož do proměnné z}
 end;
 writeln ('a*b=',s);
 writeln ('a div b=',d,' a mod b=',z);
 readkey;
end.

Změna počtu bitů

Často potřebujeme opravit šestnáctibitové číslo na osmibitové a naopak. Při této změně může ale dojít ke ztrátě informace v případě úbytku bitů. Převod čísel bez znaménka provedeme nejjednodušeji využitím půlení registrů.

  • Slabika -> Slovo
    Do šestnáctibitového registru načteme do dolní poloviny slabiku. Horní polovinu nulujeme. Slovo potom načteme ze všech šestnácti bitů:
    var b:byte;
        w:word;
    begin
     b:=10;
     asm
      MOV AL,b  {do AL osm bitů z proměnné b}
      MOV AH, 0 {nuluj AH}
      MOV w, AX {do proměnné w vlož všech šestnáct bitů}
     end;
    end.
  • Slovo-> Slabika
    Operace je opačná. Šestnáctibitové číslo vložíme do celého šestnáctibitového registru. Do slabiky potom vložíme jen spodních osm bitů. Ale pozor, tady může dojít ke ztrátě bitů v horních osmi bitech. Protože úprava čísel se znaménky by byla složitá, přichází opět na pomoc ASM86 s instrukcemi:
    • CBW - převeď obsah AL do AX se zachováním znaménka
    • CWD - převeď obsah AX do DX, AX (32 bitů) se zachováním znaménka

Práce s čísly v kódu BCD

Čísla v BCD kódu mohou být uložena v těchto formátech:

  • Nezhuštěný tvar
    V jedné slabice je uložena jedna číslice v BCD kódu. Má hodnotu 0-9 a obsazuje tedy jen spodní 4 bity. Horní polovina slabiky je nulová (to se doporučuje pro operace násobení a dělení, pro sčítání a odčítání může mít libovolný obsah). Tento tvar je vhodný pro převod do kódu ASCII. Stačí jen k slabice přičíst číslo 48 (logický součet s číslem $30).
  • Zhuštěný tvar
    V jedné slabice jsou uloženy dvě BCD číslice. Spodní 4 bity nesou hodnotu nižšího řádu (jednotky), horní 4 nesou hodnotu vyššího řádu (desítky). Do slabiky jde tedy uložit číslo v rozsahu 0-99. ASM86 nepodporuje přímo matematické operace s takto kódovanými čísly. Přesto obsahuje instrukce pro jejich úpravu po provedení běžných operací určených pro čísla v přirozeném dvojkovém kódu (obyčejné dvojkově uložené číslo). V ASM86 nejdeme i instrukce, které pro tyto operace čísla v BCD kódu připraví. Jedná se o instrukce: AAA, AAD, AAM, AAS, DAA, DAS (bližší informace v
    tabulce instrukcí).
Směr