Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Флоренсов А.Н. УП Системное программное обеспечение.docx
Скачиваний:
46
Добавлен:
28.06.2021
Размер:
148.95 Кб
Скачать

3.5. Неарифметические операции над кодами

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

Для выполнения поразрядной логической операции И служит команда с мнемокодом AND, имеющая общий вид

AND операнд1, операнд2

Основное практическое применение эта команда имеет с константным вторым операндом, который в этом случае называют маской логической операции. Команда AND с маской применяется для выборочного сброса в нуль отдельных битов двоичного кода первого операнда. (Такое действие основано на обычных, хорошо известных свойствах логической операции И: x&0=0, x&1=x.) Например, команда

AND al, 3Fh

сбрасывает в нуль два старших бита двоичного кода в регистре AL.

Для выполнения поразрядной логической операции ИЛИ служит команда с мнемокодом OR, имеющая общий вид

OR операнд1, операнд2

Основное практическое применение эта команда имеет также с константным вторым операндом – маской логической операции ИЛИ. Команда OR с маской применяется для выборочной установки (в единицу) отдельных битов двоичного кода первого операнда. (Такое действие основано на обычных, хорошо известных свойствах логической операции И: xv0=x, xv1=1.) Например, команда

OR dx, 8001h

устанавливает в единицу старший и младший биты двоичного кода в регистре DX.

Менее употребительной является команда исключающего ИЛИ, задаваемая мнемокодом XOR и употребляемая обычно также с константой – маской в качестве второго операнда. В общем случае она имеет вид

XOR операнд1, операнд2

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

Последняя из логических команд выполняет операции поразрядного инвертирования двоичного кода единственного ее операнда и имеет вид

NOT операнд

Команды сдвига представлены множеством модификаций. Основными в большинстве применений являются команды с мнемокодами SHL и SHR, наименования которых восходят к английским словам Shift, Left и Right. Эти команды задают сдвиг двоичного кода в первом операнде на число разрядов, заданное во втором операнде. В настоящее время основные формы этих команд задаются следующими схемами:

SHL операнд1, число

SHR операнд1, число

Биты, вдвигаемые в этих командах, всегда нулевые. Кроме перечисленных команд, имеются еще команды арифметического сдвига SAL, SAR и циклического сдвига ROL, ROR, RCL, RCR. Из-за редкого их использования они не будут рассматриваться в данном пособии.

Далее в листинге 3.5.1 приведена программа, демонстрирующая изложенный выше материал. В этой программе содержатся подпрограммы вывода на экран содержимого регистров AL, AX и EAX в виде шестнадцатеричных представлений. Причем процедура call wrhex_hal отображает на экране значение только младшей половины регистра AL, выдавая его всегда в виде одной шестнадцатеричной цифры. Процедура wrhex_al выдает содержимое регистра AL в виде двух шестнадцатеричных цифр, процедура wrhex_ax выдает содержимое регистра AX в виде четырех шестнадцатеричных цифр, а процедура wrhex_eax выдает содержимое регистра EAX в виде восьми шестнадцатеричных цифр.

; Использование процедур.

GLOBAL _start

SEGMENT .text

_start: mov al, 0d5h

call wrhex_hal

call wrcrlf

mov al, 0fah

call wrhex_al

call wrcrlf

mov ax, 05e7bh

call wrhex_ax

call wrcrlf

mov eax, 03fec5e7bh

call wrhex_eax

call wrcrlf

mov eax,1

int 80h ; function=exit for Linux

; procedure wrcrlf

wrcrlf:

pusha

mov eax,4 ; N function=write

mov ebx,1; N handle=1 (stdout)

mov edx,1; number of byte

mov ecx, crlf ; address of crlf

int 80h

popa

ret

; end procedure wrcrlf

; procedure wrhex_hal

wrhex_hal: push eax

push ebx

push ecx

push edx

and al, 0Fh

cmp al, 10

jge hexa

add al, '0'

jmp wrchar

hexa: add al,'A'-10 ; из AL вычесть 10 и прибавить значение 'A'

wrchar:

mov [cha],al

mov eax,4 ; N function=write

mov ebx,1; N handle=1 (stdout)

mov edx,1; number of byte

mov ecx, cha ; address of cha

int 80h

pop edx

pop ecx

pop ebx

pop eax

ret

; end procedure wrhex_hal

; procedure wrhex_al

wrhex_al: push eax

shr al,4

call wrhex_hal

pop eax

call wrhex_hal

ret

; end procedure wrhex_al

; procedure wrhex_ax

wrhex_ax: push eax

shr ax,8

call wrhex_al

pop eax

call wrhex_al

ret

; end procedure wrhex_ax

; procedure wrhex_eax

wrhex_eax: push eax

shr eax,16

call wrhex_ax

pop eax

call wrhex_ax

ret

; end procedure wrhex_eax

SEGMENT .data

crlf db 10

cnt dd 0

cha db 0

Листинг 3.5.1. Вывод шестнадцатеричного значения из регистров AL, AX, EAX

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

Во всех приведенных процедурах используется сохранение регистров и восстановление их из стека. Причем в процедуре wrcrlf для этого применены универсальные команды PUSHA и POPA, а в остальных процедурах сохраняются и восстанавливаются только действительно изменяемые в них регистры.

Основную работу для всех процедур выполняет подпрограмма wrhex_hal, предназначенная для вывода значения младшей половины регистра AL в виде одной шестнадцатеричной цифры. В ее начале содержимое регистра AL изменяется обнулением битов в старшей половине регистра. Для этих целей использована команда логического поразрядного умножения на константу 0fh. После этого выполняется сравнение промежуточного результата (значения младшей половины) с константой 10.

Если рассматриваемое значение меньше 10, то шестнадцатеричная цифра представляется обычной десятичной цифрой, и в этом случае используется уже изученная выше технология получения выводимой цифры путем прибавления к ее значению кода цифры '0'. В противном случае следует вычесть из промежуточного результата значение 10, получив тем самым числовое смещение требуемого кода от самой меньшей по значению шестнадцатеричной цифры, изображаемой буквой 'A'. Затем добавить к очередному результату значение кода буквы 'A' (что и порождает код шестнадцатеричной цифры, изображаемой соответствующей буквой). Две последние операции оказалось возможным объединить в одну с помощью команды

add al,'A'-10

которая прибавляет к промежуточному значению в регистре AL значение константы, сформированной из разности кода буквы 'A' и числа 10.

Далее подготовленное в регистре AL значение любой возможной шестнадцатеричной цифры выводится с помощью традиционной последовательности команд, обеспечивающих вызов системной функции write. Причем, соответственно с требованиями организации обращения выводимое значение переносится из регистра AL в однобайтовое служебное поле данных с именем cha.

Процедура wrhex_al строится уже проще на основе использования процедуры wrhex_hal. В начале из аргумента – регистра AL – сдвигом на 4 бита в младшую половину регистра помещается его бывшая старшая половина. Затем обращением call wrhex_hal на экран выводится шестнадцатеричная цифра, отвечающая значению этой старшей половины. Потом в регистре AL восстанавливается первоначальное значение, бывшее в нем при обращении к данной подпрограмме call wrhex_hal. С этой целью ранее запомненное для сохранения значение всего регистра EAX восстанавливается командой pop eax. Далее опять вызывается подпрограмма wrhex_hal, которая выводит в виде шестнадцатеричной цифры значение младшей половины регистра AL. Тем самым отображаются обе шестнадцатеричные цифры значения всего регистра AL, причем в правильном порядке. Заметим, что какое-либо восстановление регистров после последнего вызова уже не требуется, так как после восстановления значения регистра EAX никаких изменений регистров в текущей процедуре wrhex_al не происходит. Это, в частности, демонстрирует, что общее правило восстановления регистров может в конкретных ситуациях видоизменяться.

Процедуры wrhex_ax и wrhex_eax построены очень похоже на процедуру wrhex_al, они отличаются только тем, что на первом этапе содержимое регистров AX и EAX сдвигается на 8 и 16 бит. Тем самым вначале для промежуточного вывода задается старшая половина соответствующего регистра, а затем, после восстановления значения регистра eax, используется отображение содержимого младшей половины этого регистра. Отображения же указанных половин выполняется вызовом процедур wrhex_al и wrhex_ax.

В основной части программы после занесения в регистры AL, AX и EAX констант 0fah, 05e7bh и 03fec5e7bh осуществляются вызовы процедур wrhex_al, wrhex_ax и wrhex_eax соответственно, что обеспечивает демонстрацию использования этих процедур.