7. cvičení

Aritmetika s velkými čísly

  • ADC cíl, zdroj - stejně jako ADD, ale přičti i bit CF, používá se ihned za instrukcí ADD pro součet velkých čísel uložených ve dvojicích registrů
  • SBB cíl, zdroj - stejně jako SUB, ale odečti i bit CF, používá se ihned za instrukcí SUB pro odečtení velkých čísel uložených ve dvojicích registrů

mov eax, 0
mov ax, 123
mov bx, 246
add al, bl
adc ah, bh

Instrukce posuvů a rotací

Tyto instrukce jsou velmi dobrým pomocníkem každému, kdo je umí používat. Jedná se o bitový posuv uvnitř paměťového místa (slabiky, slova, nebo dvojslova). Při instrukcích posuvů jsou bity, které jsou z místa vysunuty ven, ztraceny (poslední vysunutý bit je přenesen do příznaku CF). Rotace jsou takové posuvy, u kterých se vysunuté bity opět do místa postupně vsunou z druhé strany, tj. bity jsou v paměťovém místě rotovány. Pozice bitů jsou v paměťovém místu číslovány od 0 vzestupně od nejméně významných k významnějším (zprava doleva, paměťové místo se kreslí s nějméně významnými bity vpravo). V následujících instrukcích je cíl, ve kterém budou bity posouvány, specifikován použitým registrem, nebo označením paměťového místa, a počet posunutí je zadán buď přímo 8-bitovým číslem, nebo je v registru CL (musí se uvést).

Posuvy:

  • SHL / SAL cíl, počet - logický/aritmetický posuv vlevo, bity se přesunou o jednu pozici výše (vlevo), do nejnižšího bitu se uloží nula, vysunutý bit se přesune do vlajky CF, to celé počet-krát
  • SHR cíl, počet - logický posuv vpravo, bity se přesunou o jednu pozici níže (vpravo), do nejvyššího bitu se uloží nula, vysunutý bit se přesune do vlajky CF, to celé počet-krát
  • SAR cíl, počet - aritmetický posuv vpravo, bity se přesunou o jednu pozici níže (vpravo), přičemž nejvyšší bit se kopíruje, vysunutý bit se přesune do příznaku CF, to celé počet-krát

Rotace:

  • ROL cíl, počet - rotace vlevo, bity se přesunou o jednu pozici výše (vlevo), do nejnižšího bitu se uloží vysunutý bit, který se také uloží do příznaku CF, to celé počet-krát
  • ROR cíl, počet - rotace vpravo, bity se přesunou o jednu pozici níže (vpravo), do nejvyššího bitu se uloží vysunutý bit, který se také uloží do příznaku CF, to celé počet-krát
  • RCL cíl, počet - rotace přes CF vlevo, bity se přesunou o jednu pozici výše (vlevo), do nejnižšího bitu se uloží bit v CF, vysunutý bit se uloží do příznaku CF, to celé počet-krát
  • RCR cíl, počet - rotace přes CF vpravo, bity se přesunou o jednu pozici níže (vpravo), do nejvyššího bitu se uloží bit v CF, vysunutý bit se uloží do příznaku CF, to celé počet-krát

Použití posuvů a rotací

Zjištění hodnoty jednotlivých bitů

Jestliže potřebujeme zjistit, jakou hodnotu nese některý z bitů místa, stačí jej posunout nebo rotovat doprava. Hodnotu, kterou bit nese, potom obdržíme ve vlajce CF. Tento způsob je samozřejmě destruktivní. Např. pro zjištění hodnoty 3. bitu (počítáno zprava od 0) provedeme SHR reg, 4.

„Bitové“ instrukce

Pomocí dosud uvedených instrukcí logických operací nelze (přímo) operovat s jednotlivými bity operandů, pouze s celými operandy (slabikami, slovy nebo dvojslovy). Tento nedostatek se úspěšně řešil maskováním nebo posuvy, ale to zřejmě nebylo dostatečně rychlé (bylo potřeba několik instrukcí) a tak procesory 386 a novější mají instrukční sadu rozšířenou o instrukce pracující s jednotlivými bity operandů. Jsou to instrukce zjištění hodnoty, nastavení a invertování hodnoty bitu. Tyto nové instrukce číslují bity od 0 zprava doleva. Možné kombinace operandů jsou registr - hodnota (pouze 8-bitová), paměť - hodnota (8-bitová), registr - registr a paměť - registr (16-bitové).

  • BT cíl, index - zkopíruje bit cíle s číslem index do příznaku CF
  • BTS cíl, index - zkopíruje bit cíle s číslem index do příznaku CF a pak jej nastaví do log. 1
  • BTR cíl, index - zkopíruje bit cíle s číslem index do příznaku CF a pak jej nastaví do log. 0
  • BTC cíl, index - zinvertuje bit cíle s číslem index a pak jej zkopíruje do příznaku CF
Kromě těchto základních instrukcí obsahují procesory 386 a novější ještě instrukce vyhledávání prvního/posledního bitu nastaveného do log. 1, BSF a BSR, což se může hodit např. u násobení pomocí posuvů a sčítání.

Tvorba masky

Masku s nastaveným určitým bitem do log. 1 můžeme vytvořit použitím instrukce posuvu nebo rotace doleva na číslo 1. Např. pro vytvoření osmibitové masky s nastaveným 3. bitem (00001000) provedeme např. MOV AL, 1; SHL AL, 3.

Vymaskování slabiky nebo slova

Často potřebuje programátor nastavit některé bity do hodnoty log. 1, nebo 0. K tomu mu velmi dobře poslouží právě logické operace AND nebo OR. Máme-li slabiku ve tvaru XXXXAXXX v registru AL a chceme, aby bity X měly hodnotu 0 a hodnota bitu A zůstala zachována, provedeme instrukci AND AL, 08h (=00001000b). Máme-li slabiku ve tvaru XXXXAXXX v registru AL a chceme, aby bity X měly hodnotu 1 a hodnota bitu A zůstala zachována, provedeme instrukci OR AL, F7h (=11110111b).

Prohození polovin bitové reprezentace hodnoty

Užitečným použitím rotací je prohození polovin bitové reprezentace hodnoty. Typicky u 32-bitových registrů pro všeobecné použití. Tyto registry se dělí na 16-bitové poloviny, avšak jménem lze přistupovat pouze ke spodní polovině (např. u EAX lze pracovat se spodní polovinou AX). Pokud potřebujeme horní polovinu, můžeme je prohodit pomocí rotace (jedno jestli vpravo nebo vlevo) o 16 pozic, např. ROL EAX, 16.

Celočíselné násobení a dělení mocninou 2

Je to nejdůležitější použití posuvů. Vychází z faktu, že efekt bitového posuvu čísla doleva o jednu pozici je stejný, jako bychom číslo vynásobili dvěma. Naopak bitový posuv čísla doprava o jednu pozici je totéž jako dělení čísla dvěma. Pozor! Toto násobení, resp. dělení je sice velmi rychlé (nejrychlejší možné), ale použitelné jen pro násobení, resp. dělení mocninou 2. Ke zjištění zbytku po celočíselném dělení mocninou 2 použijeme maskování (jak bylo popsáno výše).

Násobení konstantou

Jedná se o velice rychlé násobení čísla libovolnou konstantou (pokud je tato konstanta dostatečně malá, je rychlejší než instrukce MUL). Myšlenka je taková, že konstantu vyjádříme jako součet mocnin 2 (co nejvyšších) a číslo potom násobíme těmito mocninami 2 a tyto mezivýsledky sečteme. Naznačený postup se samozřejmě dá zobecnit na násobení předem neznámým číslem, tj. ne konstantou!
Postup v Assembleru: Číslo posuneme doleva o počet pozic rovnající se pozici log. 1 v binárním vyjádření konstanty (počítáno od 0 zprava doleva). Posuneme ho tolikrát, kolik těch log. 1 je, ale vždy posouváme původní číslo. Mezivýsledky (posuvy čísla) sečteme a máme výsledek.

Příklad vynásobení čísla konstantou 18 = 00010010:

	    MOV AX, cislo
	    MOV BX, AX
	    SHL AX, 1
	    SHL BX, 4
	    ADD AX, BX
	    MOV cislo, AX
	    

Úkoly

  1. Napište v Assembleru funkci (funkci, jejíž tělo tvoří jediný blok Assembleru), která bude mít dva parametry - pozici p a počet n. Funkce bude vracet 32-bitovou masku, ve které bude nastaveno n bitů od pozice p (včetně, počítáno od 0 zprava doleva).
  2. Napište v Assembleru funkci, která bude mít čtyři parametry - 32-bitové číslo x, mocnitel n a dva ukazatele na 32-bitová čísla. Funkce uloží na adresy určené ukazateli celočíselný podíl a zbytek dělení čísla x n-tou mocninou 2.
  3. Napište v assembleru kód, který sečte a odečte 64bitové čísla uložené v dvouregistrech EBX:EAX a EDX:ECX.
  4. Napište v jazyce C funkci unsigned int rol(unsigned int r, unsigned n), která se bude chovat jako instrukce ROL z instrukční sady procesorů x86, r je hodnota s níž se má provést rotace a n odpovídá počtu bitů, o které se má rotovat. Předpokládejte, že n je z intervalu [0; 31]. Použijte instrukci bitových posunů, nepoužívejte cyklus.
  5. Napište funkci, která vynásobí vstupní celočíselnou hodnotu číslem 25. Použijte operace bitové posunu.
  6. Na platformě ARMv7 jsou přímé hodnoty v instrukcích uloženy jako sekvence dvanácti bitů RRRR IIII IIII. Kde RRRR představuje čtyřbitové celé neznaménkové číslo ror4 a IIII IIII celé neznaménkové číslo imm8. Výsledná hodnota imm32 odpovídá imm32 = ror(zeroExtend32(imm8), ror4 * 2), kde funkce zeroExtend32 rozšíří osmibitovou hodnotu na 32bitovou hodnotu a doplní nuly a operace ror představuje operaci rotace doprava.
    1. Napište funkci void arm_decode_parts(unsigned short n, struct arm_num *decoded), která rozloží číslo n představující hodnotu uloženou ve výše zmíněném formátu a uloží jej do struktury decoded. Předpokládejte, že nevyužité horní čtyři bity mohou být nasteveny libovolně a struct arm_num odpovídá struct arm_num { unsigned char ror4; unsigned char imm8; }
    2. Napište funkci unsigned int arm_decode(unsigned short n), která vrátí hodnotu čísla uloženou ve výše zmíněném kódování. Předpokládejte, že nevyužité horní čtyři bity mohou být nasteveny libovolně.
    3. Napište funkci int arm_encodable(unsigned int n), která vrátí nenulovou hodnotu, pokud je možné číslo n uložit ve výše zmíněném kódování, jinak vrací 0.
    4. Napište funkci unsigned short arm_encode(unsigned int n), která převede číslo n do výše zmíněho kódování, nevyužité bity nechte 0.

Pro získání bodového hodnocení je potřeba splnit úkoly 3, 4, 5 a 6. Úlohu č. 6 řešte nejdříve v C a pak v assembleru.


Last update on 4. 4. 2017 19:04
Powered by Schemik.

© Petr Krajča, 2010, 2012
petr.krajca (at) upol.cz