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
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
- 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).
- 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.
- Napište v assembleru kód, který sečte a odečte 64bitové čísla uložené v dvouregistrech EBX:EAX a EDX:ECX.
- 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 an
odpovídá počtu bitů, o které se má rotovat. Předpokládejte, žen
je z intervalu [0; 31]. Použijte instrukci bitových posunů, nepoužívejte cyklus. - Napište funkci, která vynásobí vstupní celočíselnou hodnotu číslem 25. Použijte operace bitové posunu.
- 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é čísloror4
aIIII IIII
celé neznaménkové čísloimm8
. Výsledná hodnotaimm32
odpovídáimm32 = ror(zeroExtend32(imm8), ror4 * 2)
, kde funkcezeroExtend32
rozšíří osmibitovou hodnotu na 32bitovou hodnotu a doplní nuly a operaceror
představuje operaci rotace doprava.- Napište funkci
void arm_decode_parts(unsigned short n, struct arm_num *decoded)
, která rozloží číslon
představující hodnotu uloženou ve výše zmíněném formátu a uloží jej do strukturydecoded
. Předpokládejte, že nevyužité horní čtyři bity mohou být nasteveny libovolně astruct arm_num
odpovídástruct arm_num { unsigned char ror4; unsigned char imm8; }
- 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ě. - Napište funkci
int arm_encodable(unsigned int n)
, která vrátí nenulovou hodnotu, pokud je možné číslon
uložit ve výše zmíněném kódování, jinak vrací 0. - Napište funkci
unsigned short arm_encode(unsigned int n)
, která převede číslon
do výše zmíněho kódování, nevyužité bity nechte 0.
- Napište funkci
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.