Считывание из порта ввода/вывода
1) ins op1, DX
2) insb
3) insw
4) insd ; i386 и >
Эти команды считывают из порта ввода/вывода, номер которого содержится в регистре DX, байт (insb), слово (insw) или двойное слово (insd) и пересылает их в память по адресу ES:DI или ES:EDI. Команда 1) принимает одну из форм 2), 3), 4) в зависимости от типа операнда.
При использовании с префиксом rep она считывает из порта ввода/вывода блок данных (байтов, слов или двойных слов) длинной, определяемой регистром CX (ECX) и пересылает в память по адресу приемника.
Запись в порт в/в содержимого ячейки памяти, размером в байт, слово или дв. слово, находящейся по адресу DS:SI или DS:EDI
1) outs DX, op2
2) outsb
3) outsw
4) outsd ; i386 и >
Номер порта в командах работы с портами в/в должен находиться в регистре DX. В команде outs можно заменить DS на ES, FS, GS, CS SS. Используя префикс rep можно переслать в порт блок данных размером в (CX) или (ECX) байтов, слов или двойных слов.
Команды управления флагами.
После выполнения команд со строками изменяется содержимое регистров – индексов в зависимости от значения флажка направления DF. Автоматически его значение не изменяется, его должен изменить программист с помощью команд:
cld ; CLear Df, DF = 0
std ; SeT Df, DF = 1
Программист может установить следующие флажки:
stc ; CF = 1
clc ; CF = 0
cmc ; инвертировать флаг переноса
lahf ; копирует младший байт регистра FLAGS а AH
sahf ; из AH загружает флажки SF, ZF, AF, PF, CF
cli ; IF = 0
sti ; IF = 1
salc ; установить регистр AL в соответствии с CF
Загрузка сегментных регистров
lds op1, op2
les op1, op2
lfs op1, op2
lgs op1, op2
lss op1, op2
Первый операнд регистр. Для всех команд op2 – переменная в ОП размером в 32 или 48 бит в зависимости от разрядности операндов. Первые 16 бит этой переменной загружаются в соответствующий сегмент DS, ES и т.д., а следующие 16 или 32 - в регистр общего назначения, указанный в качестве первого операнда. В защищенном режиме значение, загружаемое в сегментный регистр, всегда должно быть правильным селектором сегмента, в реальном режиме любое число может использоваться как селектор.
S1 DB “ABC$”
ADR DD S1
Les DI, ADR
В переменную ADR записывается полный адрес, определяемый именем S1 (Seg:Ofs). В ES записывается значение сегментной части адреса S1, а в DI ее смещение.
Пример 1 использования команд работы со строками:
X DW 100 dup (?)
Y DW 100 dup (?)
Выполнить пересылку содержимого одной области памяти в другую X = Y
CLD ; DF = 0 (просмотр строки слева направо)
Lea SI, Y ; DS:SI – начало Y
Push DS
pop ES ; (ES) = (DS)
Lea DI, X ; ES:DI –начало X
Mov CX, 100
Rep movsw
Пример 2. В строке S, состоящей из 500 символов заменить первое вхождение звездочки на точку.
CLD ; просмотр строки слева направо
push DS
pop ES
lea DI, S ; ES:DI –начало S
mov CX, 500
mov AL, ‘ * ‘
repne scasb ; сканирование строки S и сравнение с (AL)
jne finish ; ‘ * ‘ в строке нет
mov byte ptr ES:[DI – 1], ‘ . ‘ ; замена
finish: --------------------------
Здесь используется выражение [DI – 1] т.к. после того как звездочка найдена DI увеличивается на 1 и указывает на следующий символ.
32) Работа с подпрограммами в Ассемблере, организация рекурсивных подпрограмм
Основные трудности, возникающие при реализации рекурсии – это опасность «зацикливания » рекурсии и использование параметров. Зацикливания не произойдет, если в процедуре есть рекурсивная и не рекурсивная ветви и при выполнении некоторого условия вычислительный процесс пойдет по не рекурсивной ветви.
Рекурсивное обращение ПП можно представить, если предположить, что при каждом обращении создается копия ПП и адреса возврата сохраняются в стеке. А структура стека позволяет извлекать их в последовательности, обратной поступлению.
Также решается и проблема с параметрами. В рекурсивную процедуру нельзя передавать параметры через ячейки памяти в сегменте данных, а если такая необходимость возникает, то при
входе в ПП их необходимо сохранять в стеке, а при выходе из нее восстанавливать. Это значит, что лучше сразу параметры передавать через стек.
Пример рекурсивной функции
F(n) = 1, если n = 0 или n = 1 и
F(n) = F(n – 1) + F(n – 2), если n >1
Вычисление n-го ряда Фибоначчи
Fib proc ; BX = F(n), AL = n
Cmp AL, 1
ja m1 ; если n > 1, m1
; не рекурсивная ветвь
mov BX, 1 ; если n < 1 или n = 1 BX = F(n) = 1
Ret
; рекурсивная ветвь
m1: push AX ;
dec AL ; AL = n - 1
call Fib ; BX = F(n-1)
Push BX ; сохранить в стеке F(n-1)
dec AL ; AL = n - 2
call Fib ; BX = F(n – 2)
pop AX ; AX = F(n – 1)
add BX, AX ; BX = F(n – 2) + F(n – 1)
Pop AX ; восстановить AX
Ret
Fib endp
34) Не вошедшее
Форматы данных
Процессор ix86 вместе с сопроцессором могут обрабатывать большой набор различных типов данных: целые числа без знака, целые числа со знаком, действительные числа с плавающей точкой, двоично-десятичные числа, символы, строки, указатели.
Целые числа без знака могут занимать байт, слово, двойное слово и принимать значения из диапазонов: 0 - 255, 0 - 65535, 0 – 4294967295 соответственно.
Целые числа со знаком могут занимать также байт, слово, двойное слово. Они хранятся в дополнительном коде и имеют следующий вид.
Дополнительный код положительного числа равен самому числу.
Дополнительный код отрицательного числа в любой системе счисления может быть получен по формуле: X = 10n - |X|, где n – разрядность числа.
Например, представим в слове отрицательное 16-ричное число -AC716: 104 - AC7 = F539.
Дополнительный код двоичного числа может быть получен инверсией разрядов и прибавлением 1 к младшему разряду.
Например, - 12 в байте: 1) 12 = 000011002, 2) инверсия – 111100112,
3) дополнительный код – 111101002.
Рассмотрим выполнение операции вычитания в машине: дополнительный код вычитаемого прибавляется к уменьшаемому.
Например: 65 – 42 = 23.
1) 65 = 010000012,
2) 42 = 001010102,
3) - 42 = 110101102,
4) 65 - 42 = 000101112 = 20 + 21 + 22 + 24 = 1+2+4+16=23.
Числа с плавающей точкой могут занимать 32 бита или 64 бита или 80 бит, и называются короткое вещественное, длинное вещественное, рабочее вещественное. Формат числа с плавающей точкой состоит из трех полей: <знак числа>, <машинной порядок>, <мантисса>.
короткое вещественное 1+ 8 + 23 - 10±32 - + 10±32
длинное вещественное 1+ 11 + 52 - 10±308 - + 10±308
рабочее вещественное 1+ 15 + 64 - 10±4932 - + 10±4932.
Машинный порядок(Пм) включает в себя неявным образом знак порядка и связан с истинным порядком (Пи) формулой: Пм = Пи + 12710 (102310, 1638310).
Предполагается, что мантисса нормализована и старший единичный разряд мантиссы не помещается в разрядную сетку.
Например, для короткого вещественного:
Пример, 306010 представить в виде числа с плавающей точкой, занимающего 4 байта.
1) 306010 = BF416 £ |M| <1
2) нормализуем число 0. BF4*10316
3) получим машинный порядок Пм = 316 + 7F16 = 8216
4) запишем в разрядную сетку в 2-ичной системе счисления:
0 1000 0010 011 1111 0100 0000 0000 00002
Или в 16-ричном виде: 413F400016.
0100 0001 0 011 1111 0100 0000 0000 00002
Двоично-десятичные данные - процессором могут обрабатываться 8-ми разрядные в упакованном и неупакованном формате, и сопроцессором могут обрабатываться 80-ти разрядные данные в упакованном формате. Упакованный формат предполагает хранение двух цифр в байте, а неупакованный – хранит одну цифру в цифровой части байта.
Символьные данные – символы в коде ASCII. Для любого символа отводится один байт.
Строковые данные – это последовательности бит, байт, слов или двойных слов.
Указатели– существуют два типа указателей: длинный указатель, занимающий 48 бит -селектор(16) + смещение(32) и короткий указатель, занимающий 32 бита - только смещение.