Кафедра информационных систем и программирования 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Кафедра информационных систем и программирования



Кафедра информационных систем и программирования

 

 

МИКРОПРОЦЕССОРЫ

 

 

Практикум для студентов специальности 231000 – Программная инженерия

 

Краснодар

Составители: проф. кафедры ИСП В.Н. Марков, М.В. Шатохин

УДК 681.3

 

Микропроцессоры. Практикум для студентов очной формы обучения специальности 231000 – Программноая инженерия / Сост. В.Н.Марков, М.В. Шатохин; Кубан. гос. технол. ун-т., Краснодар: Изд. КубГТУ, 2013. – 175 с.

 

Составлены в соответствии с рабочей программой курса “Микропроцессоры” для студентов специальности 231000.

Изложены принципы и приёмы программирования на языке ассемблер микропроцессоров IA-32 корпораций Intel и AMD, а также микроконтроллеров AVR.

Ил. 51. Табл. 20. Библиогр.: 2 назв.

 

 

Рецензенты:

д-р.техн.наук, проф. каф. Защиты информации в автоматизированных системах, О.А. Финько (филиал Военной академии связи)

д-р.техн.наук., Л.А. Видовский (КубГТУ)

 

 

  Ó Кубанский государственный технологический университет, 2013
 

Содержание

Предисловие ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××  
Глава 1. Ассемблер микропроцессоров IA-32 ×××××××××××××××××××××××××××××××××××  
1.1 Общие сведения о компиляторе masm32 ×××××××××××××××××××××××××××××××××××××××××  
1.2 Целочисленная арифметика. Часть 1 ××××××××××××××××××××××××××××××××××××××××××××××××  
1.3 Управление вычислительным процессом ××××××××××××××××××××××××××××××××××××××××  
1.4 Целочисленная арифметика. Часть 2 ××××××××××××××××××××××××××××××××××××××××××××××××  
1.5 Обработка данных в форматах ASCII и BCD ××××××××××××××××××××××××××××××××××  
1.6 Обработка текста ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××  
1.7 Обработка вещественных чисел ××××××××××××××××××××××××××××××××××××××××××××××××××××××××  
Глава 2. Ассемблер микроконтроллеров AVR ×××××××××××××××××××××××××××××××××  
2.1 Порты ввода-вывода ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××  
2.2 Внешние прерывания ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××  
2.3 Прерывания по переполнению таймера-счётчика ×××××××××××××××××××××××××××  
2.4 Широтно-импульсная модуляция ×××××××××××××××××××××××××××××××××××××××××××××××××××××  
Приложение А. Таблица ASCII-кодов ××××××××××××××××××××××××××××××××××××××××××××××××××××  
Приложение Б. Система команд процессоров Intel семейства IA-32 ××  
Приложение В. Краткий перечень команд обработки чисел с плавающей точкой процессоров Intel семейства IA-32 ××××××××××××××××××××××××××××××  
Приложение Г. Справка по Ассемблеру для Atmel AVR ×××××××××××××××××××××  
Библиографический список ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××  

Предисловие

Методические указания являются логическим дополнением к учебному пособию “Микропроцессоры” и состоят из двух глав и четырёх приложений.

Первая глава “Ассемблер микропроцессоров IA-32” представляет собой лабораторный практикум, включающий семь лабораторных работ. Каждая лабораторная работа содержит необходимый теоретический материал по программированию в среде masm32, подробное описание примеров, упражнения для самостоятельного выполнения, а также вопросы для самопроверки. Выполнение этого практикума позволяет овладеть основами программирования 32-разрядных Intel-совместимых процессоров, а также закрепить теоретический материал глав 1, 2 и 8 учебного пособия “Микропроцессоры”. Первая глава содержит богатый справочный материал, представленный в трёх приложениях: Таблица ASCII-кодов; Система команд процессоров Intel семейства IA-32; Краткий перечень команд обработки чисел с плавающей точкой процессоров Intel семейства IA-32.

Материал первой главы поможет студентам освоить программирование микропроцессоров как для разработки утилит и консольных приложений под платформу Windows полностью в среде masm32, так и для использования в среде высокоуровневых ЯВУ для программирования критических фрагментов приложений.

Во второй главе “Ассемблер микроконтроллеров AVR” содержит описание четырёх лабораторных работ, каждая из которых посвящена программированию основных периферийных интерфейсных схем для встраиваемых систем: порты ввода-вывода, внешние прерывания и таймеры-счётчики в различных режимах функционирования. Выполнение этой главы методических указаний позволяет овладеть основами программирования микроконтроллеров AVR, а также закрепить теоретический материал главы 13 учебного пособия “Микропроцессоры”. Вторая глава подкреплена одним приложением: Справка по Ассемблеру для Atmel AVR.

Материал второй главы поможет студентам приобрести первичные навыки разработки схемотехнических решений для простейших встраиваемых систем и освоить программирование микроконтроллеров AVR.

Вопросы для самопроверки

1. Из каких разделов состоит программа на ассемблере?

2. Что означает директива stdcall?

3. Какие команды отладчика используются для вывода данных?

4. В каких случаях шестнадцатеричное число дополняется слева нулём?

5. Какие директивы masm32 используются для определения данных и каково отличие между ними?

6. Какие поля имеет команда ассемблера?

7. Каково отличие между типами данных WORD и SWORD с точки зрения диапазона представления данных?

8. Существует ли тип данных, позволяющий хранить однобитные данные?

9. Для чего используется оператор повторения DUP?

10. Что такое множественная инициализация данных и для чего она используется?

11. Можно ли использовать множественную инициализацию для разнотипных данных?

Вопросы для самопроверки

1. В каком случае операторы SIZEOF и LENGTHOF вернут одинаковые значения?

2. Каково отличие между оператором offset и командой lea?

3. В чём отличие ближних и дальних указателей?

4. Для чего используются команды расширения целых чисел?

5. В чём отличие команды NEG и команды NOT?

6. В чём отличие формата команды IMUL от формата команды MUL?

6. Как работают трёхаргументные команды умножения целых чисел со знаком?

7. Почему размер произведения больше размера любого из множителей в два раза?

8. Для чего используются команды расширения знака делимого?

Использование стека

Команда push помещает в стек двухбайтовое число из регистра, памяти или непосредственно указанное в команде число, предварительно уменьшив содержимое указателя стека ESP на 4. Команда pop выталкивает из стека двухбайтовое число и размещает его в двухбайтовом регистре или памяти, после чего увеличивает регистр ESP на 4. Таким образом, стек растёт в сторону меньших адресов, а уменьшается в сторону б о льших адресов.

Важно соблюдать в программе баланс команд push и pop: сколько раз в программе была выполнена команда push, столько же раз должна быть выполнена команда pop. Если это правило не соблюдать, то при завершении программы будет потерян адрес возврата.

Пример 1.3.1. Ниже приведена программа, демонстрирующая различные способы работы со стеком.

.486

.model flat, stdcall

option casemap: none

include \masm32\include\windows.inc

include \masm32\include\kernel32.inc

include \masm32\include\masm32.inc

include \masm32\include\debug.inc

includelib \masm32\lib\kernel32.lib

includelib \masm32\lib\masm32.lib

includelib \masm32\lib\debug.lib

.data

Z dword 12345678h

.code

start:

mov ebx, 0AAAAAAAAh

PrintHex esp; esp=0012FFA4h

push ebx

PrintHex esp; esp=0012FFA0h

push Z

PrintHex esp; esp=0012FF9Ch

push 12345678h

PrintHex esp; esp=0012FF98h

pop Z

PrintHex esp; esp=0012FF9Ch

pop ebx

PrintHex esp; esp=0012FFA0h

pop ecx

PrintHex esp; esp=0012FFA4h

ret

end start

Упражнение 1.3.1. Определите содержимое переменной Z и используемых регистров после завершения работы программы из примера 1.3.1.

Дополнительные стековые команды:

· pushfd – помещает в стек содержимое регистра флагов EFLAGS.

· popfd – выталкивает из стека двухбайтовое число и помещает его в регистр EFLAGS.

· pushad – помещает в стек значения всех 32-разрядных регистров общего назначения в следующем порядке: EAX, ECX,EDX, EBX, ESP (то значение, которое было до выполнения команды), EBP, ESI, EDI.

· popad – выполняет обратную операцию, т.е. восстанавливает из стека значения указанных регистров в обратном порядке.

Упражнение 1.3.2. Разработайте программу вывода на печать содержимого регистра флагов в шестнадцатеричном представлении.

Вопросы для самопроверки

1. С помощью какой команды можно получить значения всех флагов?

2. Какая команда позволяет организовать цикл с заданным числом повторений?

3. Каким образом следует организовать работу со счётчиком цикла в случае вложенных циклов?

4. В чём отличие команд JZ и JE?

5. В чём отличие команд JA и JG?

6. Зачем введены синонимичные команды условных переходов?

7. Каким образом определяется адрес элемента массива по его индексу?

Битовые операции

Система команд микропроцессоров IA-32 поддерживает средства работы с отдельными битами и команды сдвига.

Команда BT (Bit Test, или тестирование бита) копирует бит первого операнда, номер n которого указан во втором операнде, во флаг переноса CF.

BT операнд, n

Первый операнд может быть 16- или 32-разрядным регистром или памятью. Второй операнд может представляться непосредственным 8-разрядным числом или регистром. Обратите внимание, когда второй операнд является регистром, его разрядность должна быть равна разрядности первого операнда. Допустимые форматы команды:

BT r/mem16, r16

BT r/mem32, r32

BT r/mem16, imm8

BT r/mem16, imm8

При выполнении этой команды значение первого операнда не изменяется. Нумерация битов начинается с нуля.

Пусть дано число 09CAh. Необходимо определить значение тринадцатого бита. Для этого вначале необходимо занести указанное число в регистр или память, а потом выполнить команду BT и проверить флаг переноса командой условного перехода JC.

mov ax, 09CAh

bt ax, 13d

jc V

PrintText “13-бит равен 0”

jmp E

V:

PrintText “13-бит равен 1”

E:

Команда BTC (Bit Test and Complement, или тестирование бита с последующей инверсией) копирует бит первого операнда, номер которого указан во втором операнде, во флаг переноса CF, а затем инвертирует значение этого бита.

Пусть дано число 09CAh. Необходимо определить значение тринадцатого бита, а потом его инвертировать. Для этого вначале необходимо занести указанное число в регистр или память, а потом выполнить команду BTC и проверить флаг переноса командой условного перехода JC.

mov ax,09CAh

PrintHex ax

btc ax, 13d

jc V

PrintText “13-бит равен 0”

PrintHex ax

jmp E

V:

PrintText “13-бит равен 1”

PrintHex ax

E:

После выполнения этой программы 13-й бит поменяет нулевое значение на единичное и регистр ax будет содержать не число 09CAh, а число 29CAh.

Команда BTR (Bit Test and Reset, или тестирование бита с последующим сбросом) копирует бит первого операнда, номер которого указан во втором операнде, во флаг переноса CF, а затем сбрасывает этот бит.

Пусть дано число 39CAh. Необходимо определить значение тринадцатого бита, а потом его сбросить. Для этого вначале необходимо занести указанное число в регистр или память, а потом выполнить команду BTR и проверить флаг переноса командой условного перехода JC.

mov ax, 39CAh

PrintHex ax

btr ax, 13d

jc V

PrintText “13-бит равен 0”

PrintHex ax

jmp E

V:

PrintText “13-бит равен 1”

PrintHex ax

E:

После выполнения этой программы 13-й бит будет сброшен и регистр ax будет содержать не число 39CAh, а число 19CAh.

Команда BTS (Bit Test and Set, или тестирование бита с последующей установкой) копирует бит первого операнда, номер которого указан во втором операнде, во флаг переноса CF, а затем устанавливает этот бит.

Пусть дано число 19CAh. Необходимо определить значение тринадцатого бита, а потом его сбросить. Для этого вначале необходимо занести указанное число в регистр или память, а потом выполнить команду BTR и проверить флаг переноса командой условного перехода JC.

mov ax, 19CAh

PrintHex ax

bts ax, 13d

jc V

PrintText “13-бит равен 0”

PrintHex ax

jmp E

V:

PrintText “13-бит равен 1”

PrintHex ax

E:

После выполнения этой программы 13-й бит будет установлен и регистр ax будет содержать не число 19CAh, а число 39CAh.

Команды логического сдвига

Команда SHL (Shift Left) выполняет логический сдвиг влево первого операнда на количество разрядов, указанных во втором операнде: SHL операнд, счётчик. Сдвигаемые младшие разряды заполняются нулями (рис.1.4.1). Последний “выдвинутый” за пределы разрядной сетки старший разряд помещается во флаг переноса CF, а бит, который до этого находился в этом флаге, теряется.

При логическом сдвиге байта, например на два разряда влево, седьмой бит будет потерян, шестой бит будет скопирован во флаг переноса CF, младшие шесть бит будут сдвинуты на два разряда влево и займут биты со второго до седьмого, а два младших бита (нулевой и первый) заполнятся нулями.

Допустимые форматы команды:

SHL reg, imm8

SHL mem, imm8

SHL reg, CL

SHL mem, CL

Последние два формата позволяют использовать регистр CL в качестве счётчика сдвига.

Пусть дано число 1111h. Для сдвига этого числа влево на три разряда достаточно выполнить две команды:

mov ax, 1111h; ax = 1111h (0001000100010001B)

shl ax, 3; ax = 8888h (1000100010001000B)

Чаще всего команда SHL используется для быстрого умножения беззнакового целого числа на число 2n. К примеру, для умножения содержимого регистра ax на число 32 достаточно сдвинуть число, находящееся в этом регистре, на 5 разрядов влево, т.к. 25 = 32.

Команда SHR (Shift Right) выполняет логический сдвиг вправо первого операнда на количество разрядов, указанных во втором операнде: SHR операнд, счётчик. Сдвигаемые старшие разряды заполняются нулями (рис.1.4.2). Последний “выдвинутый” за пределы разрядной сетки младший разряд помещается во флаг переноса CF, а бит, который до этого находился в этом флаге, теряется.

Формат команды тот же, что и команды SHL.

Пусть дано число 8888h. Для сдвига этого числа вправо на три разряда достаточно выполнить две команды:

mov ax, 8888h; ax = 8888h (1000100010001000B)

shr ax, 3; ax = 1111h (0001000100010001B)

Чаще всего команда SHR используется для быстрого целочисленного деления беззнакового целого числа на число 2n. К примеру, для деления содержимого регистра ax на число 32 достаточно сдвинуть число, находящееся в этом регистре, на 5 разрядов вправо, т.к. 25 = 32.

Команда SAL (Shift Arithmetic Left, арифметический сдвиг влево) полностью эквивалентна команде SHL, поскольку при сдвиге влево значение знакового разряда не сохраняется.

Команда SAR (Shift Arithmetic Right) выполняет арифметический сдвиг вправо первого операнда на количество разрядов, указанных во втором операнде. При этом старшие разряды заполняются значением исходного знакового разряда. Младший “выдвигаемый” разряд помещается во флаг переноса СF, а бит, который до этого находился во флаге переноса теряется (рис.1.4.3).

В командах SAL и SAR используются такие же форматы операндов, как и в командах SHL и SHR.

Пусть дано число 1111h. Для арифметического сдвига этого числа вправо на один разряд достаточно выполнить две команды:

mov ax, 1111h; ax = 1111h

sar ax, 1; ax = 0888h

Знаковый разряд числа 1111h равен нулю, поэтому старшая тетрада резуьтата сдвига также равна нулю.

Чаще всего команда SAR используется для быстрого целочисленного деления знакового целого числа на число 2n. К примеру, для деления числа -128 на число 16 достаточно арифметически сдвинуть число, находящееся в этом регистре, на 3 разряда вправо, т.к. 23 = 8:

mov ax, -128d; ax = 10000000b (-128)

sar ax,3; ax = 11110000b (-16)

Упражнение 1.4.1. Объясните, почему при делении знакового числа 0FFFFh на число 8 с помощью команды арифметического сдвига вправо результат равен исходному числу 0FFFFh.

Упражнение 1.4.2. Разработать программу вычисления значения по формуле R = 64 * X ‑ 4 * Y + (X + Y) / 128 с использованием операций сдвига. Исходные данные определены в сегменте данных в следующем виде:

X byte 156d

Y byte 100d

Упражнение 1.4.3. Разработать программу вычисления значения по формуле R = (32 * X ‑ 16 * Y +2 * X * Y) / 16 с использованием операций сдвига. Исходные данные определены в сегменте данных в следующем виде:

X byte 2d

Y byte 4d

Упражнение 1.4.4. Разработать программу вычисления значения по формуле R = (X / 16 ‑ Y / 8 + X ‑ Y) / 32 с использованием операций сдвига. Исходные данные определены в сегменте данных в следующем виде:

X byte -64d

Y byte -32d

Команда RCL (Rotate Carry Left) циклически сдвигает влево через флаг переноса каждый бит первого операнда на количество разрядов, указанных во втором операнде. При этом значение флага переноса помещается на место самого младшего бита, а самый старший (знаковый) бит числа помещается во флаг переноса CF (рис.1.4.4).

Команда RCR (Rotate Carry Right) циклически сдвигает вправо через флаг переноса каждый бит первого операнда на количество разрядов, указанных во втором операнде (рис.1.4.5).

Команда SHLD (Shift Left Double) выполняет логический сдвиг влево первого операнда на количество разрядов, указанных в третьем операнде. Освободившиеся в результате сдвига разряды первого операнда заполняются старшими битами второго операнда. При этом значение второго операнда не изменяется, но меняется состояние флагов SF, ZF, AF, PF и CF. На рисунке 1.4.6 приведён пример удвоенного сдвига влево на 4 разряда (т.е. на один 16-ричный символ): shld ax,dx,4.

Команда SHRD (Shift Right Double) выполняет логический сдвиг вправо первого операнда на количество разрядов, указанных в третьем операнде. Освободившиеся в результате сдвига разряды первого операнда заполняются младшими битами второго операнда. На рисунке 1.4.7 приведён пример удвоенного сдвига вправо на 4 разряда (на один 16-ричный символ): shrd ax,dx,4.

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

Пример 1.4.2. Алгоритм простого шифрования текстов с закрытым алгоритмом состоит в циклическом сдвиге ASCII-кодов символов шифруемого текста на некоторое количество бит влево или вправо. В приведённой ниже программе осуществляется циклический сдвиг 12-байтовой строки “012345678901” вправо на один бит.

.data

X byte "012345678901"

.code

start:

DbgDump offset X, 12d; печать исходной строки

rcr dword ptr X+8,1; сдвиг старшего двойного слова (0123)

rcr dword ptr X+4,1; сдвиг среднего двойного слова (4567)

rcr dword ptr X,1; сдвиг младшего двойного слова (8901)

jc M; проверяем флаг переноса (млад. бит переменной X)

and byte ptr X+11,7Fh; если бит=0, то сброс старшего бита X

jmp E

M:

or byte ptr X+11,80h; если бит=1, то уст-ка старшего бита X

E:

PrintLine

DbgDump offset X, 12d; печать зашифрованной строки

ret

end start

ASCII-коды исходной строки выглядят так: 3031323435363738393031, т.к. ASCII‑код символа “0” равен числу 30, ASCII‑код символа “1” равен числу 31 и т.д. После сдвига всех байтов переменной X во флаге переноса находится младший бит переменной X. Для его помещения в старший разряд переменной X осуществляется условный переход JC. Если флаг переноса равен нулю, то командой and byte ptr X+11,7Fh старший бит сбрасывается. Если флаг переноса равен единице, то командой or byte ptr X+11,80h старший бит устанавливается. В результате ASCII-коды зашифрованной строки выглядят так: 981899199A1A9B1B9C1C9818.

Упражнение 1.4.5. Разработать программу расшифрования строки (т.е. циклического сдвига в обратном направлении на один разряд), зашифрованной в примере 1.4.2. Модифицировать программу из примера 1.4.2 так, чтобы после шифрования строка расшифровывалась и выводилась на экран.

Упражнение 1.4.6. Разработать программу шифрования и расшифрования строки произвольного размера на основе циклического сдвига на один разряд вправо (при шифровании) и влево (при расшифровании). Операции шифрования/расшифрования должны быть реализованы с использованием цикла с заданным числом повторений.

Пример 1.4.3. Для быстрого умножение чисел на число не кратное 2n надо разложить множитель по степеням двойки. Пусть необходимо умножить содержимое регистра EAX на число 36. Это число можно разложить так: 36 = 32 + 4 = 25 + 22. После чего воспользоваться свойством дистрибутивности умножения:

EAX´36 = EAX´(32+4) = EAX´32 + EAX´4.

Таким образом, умножение регистра EAX сводится к выполнению двух сдвигов исходного числа на 5 и 2 бита влево с последующим суммированием полученных промежуточных результатов:

mov eax,123d; помещение исходного числа в eax

mov ebx,eax; копия исходного числа

shl eax,2; умножение исходного числа на 4

shl ebx,5; умножение копии числа на 32

add eax,ebx;сложение, eax=4428

Копия исходного числа, две операции сдвига и операция сложения выполняются за 6 тактов, а одна только операция умножения двух 32-битных регистров требует от 13 до 42 тактов.

Упражнение 1.4.7. Разработать программу умножения исходного числа 123 на число 20.

Пример 1.4.4. Очень часто для экономии памяти в один байт или в одно слово помещают несколько коротких чисел, называемых битовыми полями. Пусть в регистре AX размещено три числа: 6-битное число, 7-битное число, 3-битное число (рис.1.4.8):

Для выполнения операций с короткими числами их надо выделить из регистра AX и сохранить в байтовых переменных X, Y и Z. Чтобы выделить первое число из регистра AX достаточно сбросить два старших разряда младшего байта командой логического умножения:

mov dl,al; создаём копию младшего байта исходного числа

and dl,00111111b; сбрасываем два старших бита

mov X,dl; сохраняем первое число в переменной X

Для выделения второго числа надо сбросить биты первого и третьего числа, а потом сдвинуть содержимое регистра вправо на шесть разрядов:

mov dx,ax; создаём копию исходного числа

and dx,0001111111000000b; сбрасываем биты 1-го и 3-го чисел

shr dx,6; сдвиг вправо на 6 разрядов

mov Y,dl; сохраняем второе число в переменной Y

Для выделения третьего числа надо сбросить пять младших разрядов в старшем байте и сдвинуть содержимое байта вправо на пять разрядов:

mov dh,ah; создаём копию старшего байта исходного числа

and dh,11100000b; сбрасываем пять младших битов

shr dh,5; сдвиг вправо на 5 разрядов

mov Z,dh; сохраняем третье число в переменной Z

Упражнение 1.4.8. Выделить и сохранить день, месяц и год в отдельных переменных D, M, Y из регистра AX, содержащего следующие битовые поля: 5-битный день, 4-битный месяц и 7-битное число лет, прошедших с 1980 года (рис.1.4.9). Поэтому после выделения года к нему необходимо прибавить число 1980.

Организация условных циклов

Команда LOOPZ (Loop if Zero) позволяет организовать цикл, который будет выполняться пока установлен флаг нуля и содержимое регистра ECX, взятое без знака, больше нуля (рис.1.4.10). Метка перехода, указываемая в этой команде, должна находится в пределах –128…+127 байтов относительно адреса следующей команды.

Команда LOOPE (Loop if Equal) эквивалентна команде LOOPZ. Логика работы команд LOOPZ и LOOPE:

ECX = ECX – 1

Если (ECX>0 и ZF=1), то перейти на метку;

Иначе управление переходит следующей команде.

Команда LOOPNZ (Loop if Not Zero) позволяет организовать цикл, который будет выполняться пока сброшен флаг нуля и содержимое регистра ECX, взятое без знака, больше нуля. Команда LOOPNE (Loop if Not Equal) эквивалентна команде LOOPNZ.

Пример 1.4.5. В приведённой ниже программе выполняется перебор элементов массива 16-разрядных целых чисел со знаком до тех пор, пока не будет найден положительный элемент (т.е. тот, у которого знаковый бит равен нулю).

.data

X sword -3,-6,-9,-10,10,30,40

Y sword 0

.code

start:

mov esi, offset X; адрес первого элемента массива

mov ecx, lengthof X; длина массива

W:; начало цикла

test word ptr [esi],8000h; проверка знакового бита

pushfd; сохранение в стеке регистра флагов

add esi,type X; адрес следующего элемента массива

popfd; восстановление регистра флагов

loopnz W; если ZF<>0 и ECX>0, то цикл

jnz Q; если не нашли, то на выход

sub esi, type X; если нашли, то:

PrintDec esi; печать адреса найденного элемента mov ax,[esi]

PrintDec ax; печать значения найденного элемента

Q:

ret

end start

Команда add esi,type X модифицирует флаг нуля ZF, установленный командой тестирования знака очередного элемента массива test word ptr [esi],8000h. А команда LOOPNZ должна проверять этот флаг именно после команды проверки знака числа. Поэтому в примере 1.4.5 регистр флагов сохраняется в стеке, а после команды add esi,type X регистр флагов восстанавливается.

Если в массиве будет найден положительный элемент, то его адрес будет находиться в регистре ESI. Если же в массиве нет положительных элементов, то цикл завершится тогда, когда регистр ECX станет равным нулю (т.е. после перебора всех элементов). В этом случае следующая после LOOPNZ команда условного перехода JNZ передаст управление метке Q (т.е. выход из программы), а регистр ESI будет содержать указатель на контрольный элемент, равный нулю, расположенный сразу за массивом X и обозначенный именем Y.

Упражнение 1.4.9. Измените программу из примера 1.4.5 таким образом, чтобы программа находила первый отрицательный элемент массива:

X sword 3,6,9,10,-10,-30,-40

Упражнение 1.4.10. Измените программу из примера 1.4.5 таким образом, чтобы программа находила первый чётный элемент массива (т.е. элемент у которого младший бит равен нулю):

X sword 3,7,9,10,-10,-30,-40

Вопросы для самопроверки

1. В чём отличие логического и арифметического сдвига?

2. Через какой флаг осуществляются циклические сдвиги?

3. Какие команды сдвига можно использовать для быстрого выполнения арифметических операций умножения и деления на степени двойки?

4. Для решения каких задач преимущественно используются команды удвоенных сдвигов?

5. Какие существуют команды для организации итеративных циклов?

6. Сколько чисел складывает команда ADC?

Обработка данных в двоично-десятичном формате (BCD)

В предыдущем примере 1.5.14 деления было получено частное в ASCII-формате 30333030, которое представлялось на экране в виде 030010. Если сжать ASCII-формат, сохраняя только правые цифры каждого байта, то получим 0300. Такой формат называется двоично-десятичным (BCD - Binary Coded Decimal) или упакованным. Он содержит только десятичные цифры от 0 до 9. Длина двоично-десятичного представления в два раза меньше ASCII-представления. Преобразование чисел из ASCII-формата в BCD-формат и обратно может выполняться как справа налево (от младших к старшим разрядам), так и слева направо (от старших к младшим разрядам). Ниже приведён способ преобразования числа 76d, хранимого в регистре ax в ASCII-формате 3736h, в упакованный формат 76h.

MOV AX,3736h; ax = 3736h (0011 0111 0011 0110b)

SHL AL,4; ax = 3760h (0011 0111 0110 0000b)

SHL AX,4; ax = 7600h (0111 0110 0000 0000b)

После второго сдвига регистр ah содержит упакованное число 76h.

В двоично-десятичном представлении (BCD-формате) можно выполнять сложение и вычитание чисел. Для этих целей имеются две корректирующие команды:

DAA (Decimal Adjustment for Addition - десятичная коррекция после сложения)

DAS (Decimal Adjustment for Subtraction - десятичная коррекция после вычитания)

Пример 1.5.15. Следующая программа демонстрирует сложение трёхбайтовых чисел в BCD-формате. Числа 22334510 и 91223310 хранятся в переменных X и Y соответственно. Окончательный четырёхбайтовый результат записывается в переменную Z.

.data

X byte 22h, 33h, 45h; первое слагаемое 223345h

Y byte 91h, 22h, 33h; второе слагаемое 912233h

Z byte lengthof X + 1 dup (0); рез-тат на 1 байт больше

.code

start:

mov esi,lengthof X-1; индекс младшего байта слагаемых

MOV ecx,lengthof X; счётчик цикла

CLC; сброс флага переноса перед ADC

ZZZ:; начало цикла

MOV al,X[esi]; загрузить байт первого слагаемого

ADC al,Y[esi]; прибавить байт второго слагаемого

DAA; десятичная коррекция

MOV Z[ecx],al; записать байта результата

DEC esi; индекс следующего байта слагаемых

LOOP ZZZ; цикл

ADC ah,0; получение в ah флага переноса

MOV Z[ecx],ah; записать старшего байта результата

DbgDump offset Z, lengthof X + 1; просмотр результата

invoke ExitProcess, 0

end start

Упражнение 1.5.13. Разработать программу сложение шестибайтных чисел в BCD-формате. Числа 109234057836 и 902861069427 хранятся в переменных X и Y соответственно. Семибайтный результат разместить в переменной Z.

Упражнение 1.5.14. Разработать программу вычитания из шестибайтного числа 902861069427, представленного в BCD-формате, числа 109234057836, также представленного в BCD-формате. Указанные числа должны храниться в переменных X и Y соответственно. Шестибайтный результат разместить в переменной Z.

Вопросы для самопроверки

1. Чем отличаются API-функции обработки ANSI и Unicode-строк?

2. Какие бывают дескрипторы терминала Win-32 приложения?

3. Дайте характеристику режимов стандартного устройства ввода.

4. Дайте характеристику режимов стандартного устройства вывода.

5. Какие параметры используются при вызове api-функции вывода в окно?

6. Какая информация составляет цветовой атрибут символа?

7. С какой целью выполняется коррекция при обработке данных в ASCII-формате?

8. Что такое упакованный формат данных?

9. Зачем используются команды десятичной коррекции после сложения и вычитания?

Обработка текста

Команды обработки строк

Команды, изученные на предыдущих занятиях, оперировали одним байтом, одним словом или одним двойным словом. Однако часто бывает необходимо переслать или сравнить поля данных, длина которых значительно превышает двойное слово. Например, необходимо сравнить поля данных для того, чтобы отсортировать их в восходящей последовательности. Элементы такого формата известны как строковые данные и могут быть как символьными, так и числовыми. Для обработки строковых данных ассемблер имеет пять команд обработки элементов строк (строковых примитивов), указанных в таблице 1.6.1.

Таблица 1.6.1. Команды обработки строковых примитивов

Команда Название Описание
MOVSB MOVSW MOVSD Move string byte Move string word Move string dword Копировать целочисленные данные из одного участка памяти в другой.
LODSB LODSW LODSD Load accumulator byte (al) from string Load accumulator word (ax) from string Load accumulator dword (eax) from string Загрузить значение из памяти в аккумулятор (регистр AL, AX или EAX).
STOSB STOSW STOSD Store string from accumulator byte (al) Store string from accumulator word (ax) Store string from accumulator dword (eax) Записать содержимое аккумулятора (регистра AL, AX или EAX) в память.
CMPSB CMPSW CMPSD Compare string byte Compare string word Compare string dword Сравнить содержимое двух областей памяти, размером один байт, одно слово или одно двойное слово.
SCASB SCASW SCASD Scan string byte Scan string word Scan string dword Сравнить содержимое аккумулятора (регистра AL, AX или EAX) с содержимым памяти.

Цепочечная команда может быть закодирована для повторяющейся обработки одного байта, одного слова или одного двойного слова за одно выполнение. Например, можно выбрать "однобайтную" команду для обработки строки с нечетным числом байт или "двухбайтную" команду для обработки четного числа байт, или "четырёхбайтную" команду для обработки строк длинной, кратной четырём байтам.

Префикс повторения цепочечной команды

Сами по себе команды обработки строковых примитивов выполняют только одну операцию над элементом строки (байтом, словом, двойным словом). Однако если перед ними указать префикс повторения REP, то выполнение команды будет повторено столько раз, сколько указано в регистре ECX. При выполнении цепочечной команды с префиксом REP происходит уменьшение на 1 значения в регистре ECX до нуля. Таким образом, с помощью префикса повторения можно выполнять обработку целого массива с помощью всего одной команды. Существует несколько типов префиксов повторения (табл. 1.6.2).

Таблица 1.6.2. Префиксы повторения команд для обработки строковых примитивов

Префикс Описание
REP Повторять команду, пока ECX > 0
REPZ, REPE Повторять команду, пока ECX > 0 и флаг нуля установлен (ZF = 1)
REPNZ, REPNE Повторять команду, пока ECX > 0 и флаг нуля сброшен (ZF = 0)

Флаг направления



Поделиться:


Последнее изменение этой страницы: 2016-06-29; просмотров: 480; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.134.104.173 (0.23 с.)