Работать с отдельными битами операндов можно, используя логические операции и сдвиги. Однако, кроме них в системе команд x86 существуют специальные команды для работы с битами: это команды сканирования битов и команды проверки (и модификации) битов. Впервые они появились в процессоре i386. Так что сейчас вы вряд ли найдёте процессор, в котором их нет.
Команды сканирования битов
Сканирование битов выполняется командами BSF [1] и BSR [2]. Эти команды очень похожи. У них 2 операнда. Первый операнд должен быть 16-битным регистром, в него записывается результат. Второй операнд может быть 16-битным регистром или словом в памяти — это обрабатываемое значение.
Команда BSF [1] просматривает биты второго операнда от младшего к старшему и помещает индекс первого единичного бита в регистр. Биты нумеруются, начиная с нуля. Если единичный бит найден, то флаг нуля сбрасывается (ZF=0). Если все биты нулевые, то флаг нуля устанавливается (ZF=1), а значение первого операнда будет неопределённым (на разных процессорах может быть по-разному). Например, мой процессор (Athlon XP) в этом случае не изменяет значение в регистре. Пример кода:
mov ax,01011000b ;AX=58h
bsf bx,ax ;BX=3, ZF=0
xor ax,ax ;AX=0
bsf bx,ax ;BX=?, ZF=1
Команда BSR [2] отличается тем, что просматривает биты от старшего к младшему. Всё остальное также.
mov ax,01011000b ;AX=58h
bsr bx,ax ;BX=6, ZF=0
xor ax,ax ;AX=0
bsr bx,ax ;BX=?, ZF=1
Картинка для наглядности:
Команды проверки и модификации битов
Команда BT [3] копирует значение проверяемого бита в флаг CF. Вот и вся проверка! После этого можно выполнить условный переход командами JC [4] или JNC [4], в зависимости от значения бита. У команды два операнда: слово в регистре или в памяти и номер бита, который может находиться в регистре или быть непосредственным значением. Примеры использования команды:
bt ax,0 ;Проверка младшего бита AX
jc m1 ;Переход, если бит равен 1
mov cx,3 ;CX=3
bt ax,cx ;Проверка 3-го бита AX
jnc m1 ;Переход, если бит равен 0
Ещё 3 команды немного отличаются от BT [3]:
- команда BTR [5] проверяет бит и затем сбрасывает его;
- команда BTS [6] проверяет бит и затем устанавливает его в 1;
- команда BTC [7] проверяет бит и затем инвертирует его.
Эти команды удобны тем, что можно совместить проверку бита и присвоение ему нового значения.
Пример программы
Команду BT [3] можно использовать в цикле для вывода чисел в двоичном виде. Вместо команды условного перехода я использовал команду ADC [8]. Она прибавляет значение бита к коду символа. Получается ‘0’ или ‘1’. В коде используются макросы из предыдущей части [9].
include 'proc16.inc'
use16 ;Генерировать 16-битный код
org 100h ;Программа начинается с адреса 100h
jmp start
;-------------------------------------------------------------------------------
; Данные
s_1 db ' 1234h = $'
s_2 db '0ABCDh = $'
s_pak db 'Press any key...$'
;-------------------------------------------------------------------------------
start:
stdcall print,s_1 ;Вывод строки s_1
stdcall print_bin,1234h ;Вывод числа 1234h
stdcall endline ;Переход на новую строку
stdcall print,s_2 ;Вывод строки s_2
stdcall print_bin,0ABCDh ;Вывод числа 0ABCDh
stdcall endline ;Переход на новую строку
stdcall print,s_pak ;Вывод строки 'Press any key...'
mov ah,8 ;\
int 21h ;/ Ввод символа без эха
mov ax,4C00h ;\
int 21h ;/ Завершение программы
;-------------------------------------------------------------------------------
; Процедура вывода числа в двоичном виде
proc print_bin uses ax cx bx dx, value
mov bx,[value] ;Загрузка числа в BX
mov cx,15 ;Счетчик битов
mov ah,2 ;Для функции DOS 02h
@@: mov dl,'0' ;DL='0'
bt bx,cx ;Проверка бита!
adc dl,ch ;Прибавление значения бита (CH=0)
int 21h ;Вывод символа
dec cx ;Декремент счетчика
jns @b ;Переход, если неотрицательное значение
ret ;Возврат из процедуры
endp
;-------------------------------------------------------------------------------
; Процедура вывода строки
proc print uses ax dx, str
mov ah,9 ;Функция DOS 09h
mov dx,[str] ;Загрузка адреса строки в DX
int 21h ;Вывод строки
ret ;Возврат из процедуры
endp
;-------------------------------------------------------------------------------
; Процедура вывода перехода на новую строку
proc endline
call @f ;Подумайте, как это работает
db 13,10,'$'
@@: call print
ret
endp
Результат работы программы:
Упражнение
Если вам ещё не надоели упражнения… Напишите процедуру, которая сбрасывает старший единичный бит и устанавливает в единицу младший нулевой бит в регистре AX (лучше прочитать ещё раз). Результаты можете писать в комментариях.
Следующая часть » [10]