Меню

7 3 2 Арифметические и логические инструкции

7.3.2. Арифметические и логические инструкции

Список арифметических инструкций представлен в табл. 13, где показаны режимы адресации, использующие каждую инструкцию доступа к байтовому операнду. Например, команда сложения ADDможет быть записана следующим образом:

ADD A , # 127

Время выполнения команд указано в таблице для частоты тактирования 12МГц. Все арифметические инструкции выполняются за 1 мкс за исключением командыINC DPTR, — требующей 2 мкс, а также умножения и деления, выполняемых за 4 мкс. Отметим, что любой байт во внутренней памяти данных может быть инкрементирован и декрементирован без использования аккумулятора. Одна из инструкций инкрементаINCоперирует с указателем данныхрегистромDPTR, использующимся для получения 16-разрядного адреса внешней памяти данных.

Инструкция MUL ABпроизводит умножение данных в аккумуляторе на данные, находящиеся в регистре В, помещая 16-битное произведение в регистры А и В.

Инструкция DIV ABделит содержимое аккумулятора на значение в регистре В, оставляя остаток в В, а частноев аккумуляторе. Эта команда чаще используется для преобразования оснований чисел и сдвигов, чем для «арифметических» операций. В операциях сдвига деление числа на 2 n сдвигает его наn бит вправо.

Инструкция DA Aпредназначена для двоично-десятичных (BCD) арифметических операций. В BCDоперациях команды ADD и ADDC всегда следуют за командой DA A, что обеспечивает сохранение результата в представлении BCD. Однако данная команда не дает преобразование двоичного числа в двоично-десятичное, а обеспечивает правильный результат только в случае, когда применяется в качестве второго шага при сложении двух BCD байт.

Источник

Арифметические инструкции ассемблер

ассемблер

Прочитав эту статью, ты научишься пользоваться арифметическими и логическими инструкциями, а также инструкциями сдвига. Попутно узнаешь, как создавать подпрограммы. А в конце напишешь простенькую игрушку «Угадай число».

Предыдущие статьи

  1. Арифметические инструкции ассемблер
  2. Создание вспомогательной подпрограммы
  3. Сложение и вычитание
  4. Инструкция умножения
  5. Инструкция деления
  6. Логический и арифметический сдвиги, циклический сдвиг
  7. Три логические инструкции плюс одна бесполезная
  8. Инструкции инкремента и декремента
  9. Написание простой игры на ассемблере «Угадай число»
  10. Инструкции и операторы

Арифметические инструкции ассемблер

Большинство тех инструкций, о которых ты узнаешь из этой статьи, принимают на входе два аргумента. Каждый отдельно взятый аргумент — это либо регистр, либо память, либо константа. Почти все их сочетания допустимы: регистр-регистр, регистр-память, память-регистр, регистр-константа, память-константа. Единственное недопустимое сочетание — память-память.

Регистры могут быть 16- или 8-битными. 16-битные регистры: AX , BX , CX , DX , SI , DI , BP и SP . 8-битные регистры: AH , AL , BH , BL , CH , CL , DH и DL .

Создание вспомогательной подпрограммы

У всех программ, которые мы с тобой сейчас напишем, есть повторяющееся действие: вывести результат на экран. Чтобы не писать код для этого действия каждый раз заново, давай напишем для него подпрограмму.

Что такое подпрограмма? Это кусок кода, который выполняет какую-то небольшую задачу. К подпрограмме обычно обращаются через инструкцию call . Все подпрограммы заканчиваются инструкцией ret (RETurn).

Пока это все, что тебе нужно знать о подпрограммах. Конечно, по-хорошему, когда пользуешься подпрограммами, надо бы понимать еще несколько вещей, в частности что такое указатель стека и как он меняется при обращении к подпрограмме. Но пока, в рамках текущего урока, давай просто условимся, что если тебе надо нарисовать на экране букву, просто вставляй в свой код вот такую инструкцию.

Создание вспомогательной подпрограммы ассемблер

Реализация подпрограммы call display_letter представлена ниже. Сохрани ее в файл library.asm .

Создание вспомогательной подпрограммы ассемблер

Важно! В конец всех программ, которые мы напишем, тебе надо будет вставлять код из library.asm . К чему это приведет? Все программы будут заканчиваться выходом в командную строку, и у них будут подпрограммы для вывода символа на экран (из регистра AL ) и для считывания символа с клавиатуры (результат помещается в регистр AL ).

Сложение и вычитание

В качестве аргументов для инструкции сложения давай задействуем регистр AL и константу.

Сложение и вычитание ассемблер

Эта программа выводит на экран цифру 7 . Потому что 4 + 3 = 7 .

В качестве аргументов для инструкции вычитания давай возьмем регистр AL и константу.

Сложение и вычитание ассемблер

Эта программа выводит на экран цифру 1 . Потому что 4 – 3 = 1 .

Инструкция умножения

Инструкция умножения умеет работать с байтами (8-битные числа) и словами (16-битные числа). Умножаемое — это всегда регистр AL / AX . А множителем может быть либо регистр (любой), либо переменная в памяти.

Только учти, что если умножаемое у тебя в AL , то множитель должен быть 8-битным, а если в AX — 16-битным. Результат умножения попадает либо в AX (когда перемножаем два 8-битных числа), либо в DX:AX (когда перемножаем два 16-битных числа).

Читайте также:  Как обшить гипсокартоном стены пошаговая инструкция

Инструкция умножения ассемблер

В примере ниже мы используем два 8-битных регистра AL (умножаемое) и CL (множитель). Результат попадает в 16-битный регистр AX .

Эта программа выводит на экран цифру 6 . Потому что 3 × 2 = 6 .

Для того чтобы перемножить два 16-битных числа, умножаемое помести в AX , а множитель — в CX . Затем вместо mul cl напиши mul cx .

Обрати внимание, инструкция mul оперирует беззнаковыми целыми. Если тебе надо перемножить числа со знаком, используй imul .

Инструкция деления

Инструкция деления умеет работать со словами (16-битные числа) и двойными словами (32-битные числа). Делимое — это всегда либо регистр AX , либо DX:AX . А делителем может быть либо регистр (любой), либо переменная в памяти.

Только учти, что если делимое у тебя в AX , то делитель должен быть 8-битным, а если в DX:AX — 16-битным.

Когда ты делишь 16-битное число на 8-битное, то результат попадает в AL , а остаток — в AH . Если делишь 32-битное число на 16-битное, результат попадает в AX , остаток — в DX .

Инструкция деления ассемблер

В примере ниже мы используем 16-битный и 8-битный регистры. Результат попадает в AL , остаток в AH .

Эта программа выводит на экран цифру 3 . Потому что 100 / 33 = 3 . Если хочешь посмотреть, какой остаток получился, добавь вот такую строчку сразу после той, где написана инструкция div .

Инструкция деления ассемблер

Берегись! Инструкция деления может сломать твою программу. Если ты сделаешь деление на ноль, то возникнет системная ошибка и твоя программа вылетит в командную строку.

Обрати внимание, инструкция div оперирует беззнаковыми целыми. Если тебе надо разделить числа со знаком, используй idiv .

Логический и арифметический сдвиги, циклический сдвиг

Логический и арифметический сдвиги, циклический сдвиг

Инструкции сдвига (операторы и >> в языках высокого уровня) — это самые родные инструкции для процессора. Работают они быстрее, чем большинство других инструкций. Так что если какую-то часть вычислений можно реализовать на них, — особенно если это позволит избежать инструкций умножения и деления, — смело их используй.

Сейчас объясню, как здесь работает инструкция сдвига. Представь, что значение регистра AL — это число в двоичной системе счисления. Инструкция shl просто сдвигает каждый бит двоичного числа на одну позицию влево и добавляет справа ноль. А тот бит, который вытесняется слева, попадает в флаг CF (Carry Flag; флаг переноса).

Аналогичным образом работает инструкция shr , но только она сдвигает биты регистра вправо, а не влево.

Есть еще инструкция sar , которая работает почти как shr , но в отличие от shr делает не логический, а арифметический сдвиг. Что это значит? Когда sar сдвигает бит двоичного числа вправо, то не добавляет ноль, а дублирует бит, который там был до сдвига. Ииногда это может быть и ноль, но не всегда.

В чем польза от такой хитроумной альтернативы обычному сдвигу вправо? В том, что sar позволяет двигать числа со знаком. Сдвинуть их может и shr , вот только в регистре в результате этого получится белиберда.

Ты, наверное, уже понял, что вторым аргументом у всех инструкций сдвига указывается количество позиций, на которое нужно сдвинуть биты регистра. Обрати внимание: если указываешь это количество цифрой, то это может быть только единица. Если хочешь за раз сдвинуть сразу несколько битов, воспользуйся регистром CL .

Логический и арифметический сдвиги ассемблер

Еще есть инструкции для циклического сдвига: ror , rcr , rol и rcl . В чем их особенность? Биты, выдвигаемые с одного конца, появляются с другой стороны. Циклический сдвиг вправо выполняется инструкцией ror , а влево — инструкцией rol . rcr/rcl делают то же самое, что ror/rol , только задействуют еще один дополнительный бит — CF . Добавляемый бит берется из CF , а выдвигаемый попадает в CF .

У shl (логический сдвиг влево) есть синоним — sal . Две эти инструкции полностью идентичны — вплоть до того, что генерируются в один и тот же машинный код.

Три логические инструкции плюс одна бесполезная

Три логические инструкции ассемблер

В 8088 доступны три логические инструкции: and , or и xor .

Инструкция and эквивалентна оператору & в Си и JavaScript; or — оператору | , а xor — оператору ^ .

Еще есть инструкция not , которая принимает только один параметр. Она инвертирует все биты указанного регистра. ( not al эквивалентна оператору

в Си и JavaScript).

Три логические инструкции ассемблер

Кроме того, у 8088 есть инструкция neg , которая очень похожа на not , но только она делает не логическую инверсию, а арифметическую: меняет знак у заданного числа.

Читайте также:  Перечень журналов по пожарной безопасности которые должны быть на предприятии

Еще в ассемблере есть инструкция, которая не делает совершенно ничего. Ты можешь вставить ее в любое место своей программы, и она никак не повлияет на ход выполнения. Конечно, за исключением того, что программа отработает чуть медленнее. Это инструкция nop . Можешь поэкспериментировать с ней. Вставь ее куда душе угодно после директивы org , и ты увидишь, как твоя программа увеличится ровно на один байт (это размер инструкции No OPeration), но работать будет без изменений.

Инструкции инкремента и декремента

Инструкции инкремента и декремента ассемблер

Инструкции инкремента и декремента позволяют увеличивать или уменьшать на единицу значение регистра или значение переменной в памяти. Эти инструкции работают и с байтами (8 бит), и со словами (16 бит).

Тут мы:

  1. загружаем в AL ASCII-код цифры ноль, то есть 0x30 ;
  2. показываем цифру на экране;
  3. прибавляем к AL единицу;
  4. повторяем шаги 2–3 до тех пор, пока в AL не окажется 0x39 ;
  5. показываем текущий символ и делаем все то же самое, что раньше, но в обратном порядке;
  6. отнимаем от AL единицу;
  7. выводим на экран то, что получилось;
  8. повторяем до тех пор, пока в AL не окажется 0x30 .

В итоге программа выводит на экран вот такую строку: 012345678987654321 .

В этой программе есть еще одна новая для тебя инструкция — cmp (CoMPartion — сравнить). Она работает так же, как инструкция вычитания, но с одним значительным отличием: cmp не меняет значение регистра. Она меняет только биты регистра флагов ( Flags ).

Обычно cmp используется совместно с инструкциями условного перехода, такими как je (Jump if Equal — «прыгнуть, если равно»), jne (Jump if Not Equal — «прыгнуть, если не равно») и подобными.

Написание простой игры на ассемблере «Угадай число»

Ну вот, теперь ты знаешь достаточно ассемблерных инструкций, чтобы написать несложную игру «Угадай число».

Написание простой игры на ассемблере

Как она будет работать? После запуска игры компьютер загадывает число, выводит на экран знак вопроса и ждет ответа игрока. Если число, введенное игроком, отличается от того, которое загадал компьютер, игра снова выводит знак вопроса. Когда игрок наконец угадывает число, программа печатает его на экране и добавляет смайлик (знак двоеточия и закрывающую скобку). Вот ассемблерный код, который воплощает описанную задумку.

Как компьютер загадывает число? Он считывает из порта 0x40 псевдослучайное число. Этот порт подключен к микросхеме таймера. Таймер без остановки отсчитывает такты процессора. Когда ты считываешь значение с его порта, то каждый раз получаешь псевдослучайное число в диапазоне от 0x00 до 0xFF . Вот и весь секрет.

Теперь небольшой организационный момент. До сих пор, когда нам с тобой нужна была буква, мы задавали ее шестнадцатеричным ASCII-кодом. Но у компилятора NASM есть удобная особенность: ты можешь напечатать любой символ, заключить его в апострофы, и NASM сам преобразует его в ASCII-код.

Давай перепишем нашу игру, воспользовавшись этой особенностью NASM.

Написание простой игры на ассемблере

Согласись, так исходный код выглядит куда более читабельно.

Инструкции и операторы

Если ты знаешь Си, Java или JavaScript, то вот небольшая табличка соответствия между ассемблерными инструкциями, которые ты сегодня освоил, и операторами из этих языков.

Поздравляю, ты сделал небольшой шаг в освоении ассемблера! Теперь ты можешь создавать на нем небольшие игрушки. Та, которую мы с тобой сделали, занимает всего 70 байт. Для глубоко изучения ассемблера рекомендую статью «Как создать интерпретатор бейсика на ассемблере«.

Источник



Арифметические и логические инструкции

В группу арифметических команд входят инструкции, выполняющие сложение, вычитание, декремент и инкремент данных, логическое умножение, логическое сложение, операцию ИСКЛЮЧАЮЩЕЕ ИЛИ, инверсию переменной. Обычно к этой группе относят также инструкции сравнения данных. В микроконтроллере ATmegal6 реализованы также функции арифметического умножения целых чисел и дробных чисел, без знака и со знаком.

Все инструкции этой группы, как правило, приводят к изменению состояния флагов регистра состояния в соответствии с результатами выполняемой операции.

В микроконтроллерах с архитектурой AVR предусмотрено довольно много (31) инструкций, выполняющих арифметические и логические преобразования данных. Инструкции используют исключительно прямую регистровую или непосредственную адресацию данных. Операнды хранятся в регистрах общего назначения, в один из них (регистр-приемник) всегда направляется и результат вычислений.

Арифметические инструкции сложения и вычитания выполняют сложение и вычитание одно- и двухбайтных операндов. Инструкции adc (add with carry two registers) и sbc (subtract with carry two registers) используют при вычислениях флаг переноса С.

Читайте также:  Создание базы данных SQL и работа с таблицами в SQL

Инструкции логического умножения (and) и логического сложения (or) , ИСКЛЮЧАЮЩЕЕ ИЛИ (еог) преобразуют только однобайтные данные.

Инструкция дополнения до единицы com (one’s complement), фактически выполняет операцию инверсии, а инструкция дополнения до двух neg (two’s complement) — меняет знак числа.

Инструкции установки (set) позволяют установить как отдельные, так и все биты выбранного регистра в единичное состояние, а инструкции очистки (clear) — в нулевое.

Инструкции инкремента регистра ‘mc(increment) и декремента регистра dec (decrement) используют прямую адресацию одного выбранного регистра.

Тест на нуль или минус tst (test for zero or minus) фактически не меняет содержимого регистра, но устанавливает соответствующие флаги при равенстве операнда нулю или при его отрицательном значении.

Инструкции сравнения (compare) также не меняют содержимого регистров, а оценивают разность операндов и устанавливают соответствующие флаги в регистре состояния.

Шесть инструкций умножения (multiply) выполняют умножение целых и дробных операндов с учетом и без учета знака. 16-битный результат умножения всегда записывается в регистры общего назначения R0:R1.

Большинство арифметических и логических команд выполняются за один такт. Исключение составляют только инструкции с непосредственной адресацией, работающие с двухбайтными словами: adiw (add immediate to word) и sbiw (subtract immediate from word), и инструкции умножения, выполняющиеся за два такта.

Арифметические и логические инструкции

Источник

Погружение в ассемблер. Осваиваем арифметические инструкции

Содержание статьи

  • Другие статьи курса
  • Пишем вспомогательную подпрограмму
  • Учимся складывать и вычитать
  • Осваиваем инструкцию умножения
  • Разбираемся с инструкцией деления
  • Логический и арифметический сдвиги, циклический сдвиг
  • Три логические инструкции плюс одна бесполезная
  • Знакомимся с инструкциями инкремента и декремента
  • Пишем простую игрушку «Угадай число»
  • Выводы
  • Инструкции и операторы

Другие статьи курса

  • Зачем учить ассемблер в 2020 году
  • Делаем первые шаги в освоении асма
  • Как работают переменные, режимы адресации, инструкции условного перехода
  • Учимся работать с памятью
  • Работаем с большими числами и делаем сложные математические вычисления
  • Сокращаем размер программы
  • Пишем клон игры Flappy Bird, который уместится в бутсектор
  • Пишем бейсик и умещаем его в 512 байт

Большинство тех инструкций, о которых ты узнаешь из этой статьи, принимают на входе два аргумента. Каждый отдельно взятый аргумент — это либо регистр, либо память, либо константа. Почти все их сочетания допустимы: регистр-регистр, регистр-память, память-регистр, регистр-константа, память-константа. Единственное недопустимое сочетание — память-память.

Регистры могут быть 16- или 8-битными. 16-битные регистры: AX , BX , CX , DX , SI , DI , BP и SP . 8-битные регистры: AH , AL , BH , BL , CH , CL , DH и DL .

Пишем вспомогательную подпрограмму

У всех программ, которые мы с тобой сейчас напишем, есть повторяющееся действие: вывести результат на экран. Чтобы не писать код для этого действия каждый раз заново, давай напишем для него подпрограмму.

Что такое подпрограмма? Это кусок кода, который выполняет какую-то небольшую задачу. К подпрограмме обычно обращаются через инструкцию call . Все подпрограммы заканчиваются инструкцией ret (RETurn).

Пока это все, что тебе нужно знать о подпрограммах. Конечно, по-хорошему, когда пользуешься подпрограммами, надо бы понимать еще несколько вещей, в частности что такое указатель стека и как он меняется при обращении к подпрограмме. Но пока, в рамках текущего урока, давай просто условимся, что если тебе надо нарисовать на экране букву, просто вставляй в свой код вот такую инструкцию.

Реализация подпрограммы call display_letter представлена ниже. Сохрани ее в файл library.asm .

Важно! В конец всех программ, которые мы напишем, тебе надо будет вставлять код из library.asm . К чему это приведет? Все программы будут заканчиваться выходом в командную строку, и у них будут подпрограммы для вывода символа на экран (из регистра AL ) и для считывания символа с клавиатуры (результат помещается в регистр AL ).

Учимся складывать и вычитать

В качестве аргументов для инструкции сложения давай задействуем регистр AL и константу.

Эта программа выводит на экран цифру 7 . Потому что 4 + 3 = 7 .

В качестве аргументов для инструкции вычитания давай возьмем регистр AL и константу.

Эта программа выводит на экран цифру 1 . Потому что 4 – 3 = 1 .

Продолжение доступно только участникам

Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее

Источник