Главная страница Случайная страница КАТЕГОРИИ: АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника |
Арифметические команды
Изучение команд для выполнения арифметических операций начнём с команд сложения и вычитания целых чисел. Определим вид и допустимые операнды у команд сложения и вычитания: КОП op1, op2, где КОП = add, sub, adc, sbb. add – сложение, sub – вычитание: op1: = op1 ± op2 adc – сложение с учётом флага переноса, sbb – вычитание с учётом флага переноса: op1: = op1 ± op2 ± CF Таблица допустимых операндов для этих команд:
В результате выполнения операций изменяются флаги CF, OF, ZF, SF, которые отмечают соответственно за перенос, переполнение, нулевой результат и знак результата (флагу SF всегда присваивается знаковый бит результата). Эти команды меняют и некоторые другие флаги (см. [5, 9]), но это нас интересовать не будет. Далее рассмотрим команды умножения и деления целых чисел. Формат этих команд накладывает сильные ограничения на месторасположение операндов. Первый операнд всех команд этого класса явно в команде не указывается и находится в фиксированном регистре, принимаемом по умолчанию. В младшей модели семейства есть следующие команды умножения и деления, в них явно задаётся только второй операнд (второй сомножитель или делитель): mul op2 – беззнаковое умножение, imul op2 – знаковое умножение, div op2 – беззнаковое целочисленное деление, idiv op2 – знаковое целочисленное деление. Как видим, в отличие от команд сложения и вычитания, умножение и деление знаковых и беззнаковых целых чисел выполняются разными командами (по разным алгоритмам). В случае с короткими целыми операндами при умножении вычисление производится по формуле: AX: = AL * op2 При делении (операции div и mod понимаются в смысле языка Паскаль): AL: = AX div op2 AH: = AX mod op2 В случае с длинными операндами при умножении вычисление производится по формуле: (DX, AX): = AX * op2 При делении: AX: = (DX, AX) div op2 DX: = (DX, AX) mod op2 В этих командах операнд op2 может иметь формат r8, r16, m8 или m16. Как видим, команды умножения всегда дают точный результат, так как под хранение произведения выделяется в два раза больше места, чем под каждый из сомножителей. Команды деления могут вызывать аварийную ситуацию, если частное не помещается в отведённое для него место, т.е. в регистры AL и AX соответственно. Заметим, что остаток от деления всегда помещается в отводимое для него место на регистрах AH или DX соответственно (докажите это!). После выполнения команд умножения устанавливаются некоторые флаги, из которых для программиста представляют интерес только флаги переполнения и переноса (CF и OF). Эти флаги устанавливаются по следующему правилу. CF=OF=1, если в произведении столько значащих (двоичных) цифр, что они не помещаются в младшей половине произведения. На практике это означает, что при CF=OF=1 произведение коротких целых чисел не помещается в регистр AL и частично " переползает" в регистр AH, а произведение длинных целых чисел – не помещается в регистре AX и " на самом деле" занимает оба регистра (DX, AX). И наоборот, если CF=OF=0, то в старшей половине произведения (соответственно в регистрах AH и DX) находятся только незначащие двоичные цифры произведения. Другими словами, при CF=OF=0 в качестве результата произведения можно взять его младшую половину. Команды деления после своего выполнения как-то устанавливают некоторые флаги, но никакой полезной информации из значения этих флагов программист извлечь не может. Можно сказать, что деление " портит" некоторые флаги. Для написания программ на Ассемблере нам будут полезны также следующие унарные арифметические операции. neg op1 – взятие обратной величины знакового числа, op1: = -op1; inc op1 – увеличение (инкремент) аргумента на единицу, op1: = op1+1; dec op1 – уменьшение (декремент) аргумента на единицу, op1: = op1-1; Применение этих команд вместо соответствующих по действию команд вычитания и сложения приводит к более компактным программам. Необходимо также отметить, что команды inc и dec, в отличие от эквивалентных им команд add и sub никогда не меняют флаг CF. [9]
|