Учебный курс. Часть 30. Команды работы с битами

Автор: xrnd | Рубрика: Учебный курс | 13-12-2010 | Распечатать запись Распечатать запись

Работать с отдельными битами операндов можно, используя логические операции и сдвиги. Однако, кроме них в системе команд x86 существуют специальные команды для работы с битами: это команды сканирования битов и команды проверки (и модификации) битов. Впервые они появились в процессоре i386. Так что сейчас вы вряд ли найдёте процессор, в котором их нет.

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

Сканирование битов выполняется командами BSF и BSR. Эти команды очень похожи. У них 2 операнда. Первый операнд должен быть 16-битным регистром, в него записывается результат. Второй операнд может быть 16-битным регистром или словом в памяти — это обрабатываемое значение.

Команда BSF просматривает биты второго операнда от младшего к старшему и помещает индекс первого единичного бита в регистр. Биты нумеруются, начиная с нуля. Если единичный бит найден, то флаг нуля сбрасывается (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 отличается тем, что просматривает биты от старшего к младшему. Всё остальное также.

    mov ax,01011000b  ;AX=58h
    bsr bx,ax         ;BX=6, ZF=0
    xor ax,ax         ;AX=0
    bsr bx,ax         ;BX=?, ZF=1

Картинка для наглядности:

Команды проверки и модификации битов

Команда BT копирует значение проверяемого бита в флаг CF. Вот и вся проверка! После этого можно выполнить условный переход командами JC или JNC, в зависимости от значения бита. У команды два операнда: слово в регистре или в памяти и номер бита, который может находиться в регистре или быть непосредственным значением. Примеры использования команды:

    bt ax,0           ;Проверка младшего бита AX
    jc m1             ;Переход, если бит равен 1
    mov cx,3          ;CX=3
    bt ax,cx          ;Проверка 3-го бита AX
    jnc m1            ;Переход, если бит равен 0

Ещё 3 команды немного отличаются от BT:

  • команда BTR проверяет бит и затем сбрасывает его;
  • команда BTS проверяет бит и затем устанавливает его в 1;
  • команда BTC проверяет бит и затем инвертирует его.

Эти команды удобны тем, что можно совместить проверку бита и присвоение ему нового значения.

Пример программы

Команду BT можно использовать в цикле для вывода чисел в двоичном виде. Вместо команды условного перехода я использовал команду ADC. Она прибавляет значение бита к коду символа. Получается ‘0’ или ‘1’. В коде используются макросы из предыдущей части.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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 (лучше прочитать ещё раз). Результаты можете писать в комментариях.

Следующая часть »

Комментарии: