Инструкции SBFM и UBFM копируют определенное количество бит из одного регистра в другой. Они имеют следующие формы:
SBFM Xd, Xs, #r, #s UBFM Xd, Xs, #r, #s
Первый операнд - Xd указывает, в какой регистр копируются биты, а второй операнд - из какого регистра копируются биты. Третий операнд #r
задает, с какого бита в Xs
начинается копирование, а четвертый операнд - по какой бит идет копирование. В первый операнд биты копируются в самое начало.
В качестве регистров могут использоваться как 64-разрядные X0-X30, так и 32-разрядные W0-W30. SBFM учитывает знак при копировании и предназначена для чисел со знаком, а UBFM применяется для беззнаковых чисел.
Например, используем инструкцию SBFM:
mov x1, 47 // 0b00101111 sbfm x0, x1, #1, #4 // X0 = 0b000000111
Здесь в регистр X1 помещается число 47 или 0b00101111
. Далее с помощью инструкции SBFM
из регистра X1 извлекаем биты с номера 1 (нумерация начинается с нуля, поэтому бит с номером 1 по сути будет вторым битом), по бит с номером 4:
X1 = 0b00101111 X0 = 0b00000111
Таким образом, в регистр X0 будет помещаться число 0b0111
, то есть число 7. При этом инструкция SBFM применяет копирование битов со знаком - все остальные биты первого регистра
заполняются знаковым битом из второго регистра. Так, в предыдущем случае копируемое значение было равно 0111
, где старший, он же знаковый бит был равен 0. Поэтому после копирования все остальные биты в X0
получали значение 0. Но теперь извлекем из числа 47 только два бита:
mov x1, #47 // 0b00101111 sbfm x0, x1, #1, #2 // X0 = 0b11111111
Извлекаемые два бита равны 11
- старший бит здесь равен 1, следовательно, знаковый бит, которым будет заполняться первый операнд, тоже равен 1, поэтому в результате мы
получим число -1:
X1 = 0b00101111 X0 = 0b11111111
Причем это независимо от того, что во втором регистре, из которого берутся биты, находится положительное число.
Инструкция UBFM работает похожим образом, только для беззнаковых чисел:
mov x1, #47 // 0b11110111 ubfm x0, x1, #1, #2 // X0 = 0b00000011
Инструкция EXTR извлекает биты из пары регистров:
EXTR Xd, Xs1, Xs2, count
Из регистра Xs1 берутся младшие count битов, а из Xs2 берутся все биты, кроме младших count битов. Взятые из обоих регистров биты объединяются и помещаются в Xd. Например:
mov w1, #7 // 0b00000000_00000000_00000000_00000111 mov w2, #255 // 0b00000000_00000000_00000000_11111111 extr w0, w1, w2, #2 // смещение два бита // w0 = 11_000000_00000000_00000000_00111111
Здесь в качестве смещения применяется число 2. Поэтому сначала берем из второго операнда - регистра W2 2 младших бита (из
0b00000000_00000000_00000000_00000111
берем 11
), затем из третьего операнда - регистра W3 берем все биты, кроме 2 младших бита (из
0b00000000_00000000_00000000_11111111
берем 0b00000000_00000000_00000000_111111
).
Таким образом, в W0 будет располагаться число 11_000000_00000000_00000000_00111111
Для определенных форм этих инструкций также можно использовать псевдонимы:
Инструкция | Условие | Псевдоним |
SBFM Xd, Xn, #r, #s | #s == 63 | ASR Xd, Xn, #shift |
SBFM Wd, Wn, #r, #s | #s == 31 | ASR Wd, Wn, #shift |
UBFM Xd, Xn, #r, #s | #s != 63 && #s+1 == #r | LSL Xd, Xn, #shift |
#s == 63 | LSR Xd, Xn, #shift | |
UBFM Wd, Wn, #r, #s | #s != 31 && #s+1 == #r | LSL Wd, Wn, #shift |
#s == 31 | LSR Wd, Wn, #shift | |
EXTR Xd, Xn, Xm, #lsb | Xn == Xm | ROR Xd, Xn, #shift |
EXTR Wd, Wn, Wm, #lsb | Wn == Wm | ROR Wd, Wn, #shift |
Ряд инструкций выполняют извлечение битов со вставкой
BFI Xd, Xn, #lsb, #width BFXIL Xd, Xn, #lsb, #width SBFIZ Xd, Xn, #lsb, #width SBFX Xd, Xn, #lsb, #width UBFIZ Xd, Xn, #lsb, #width UBFX Xd, Xn, #lsb, #width BFI Wd, Wn, #lsb, #width BFXIL Wd, Wn, #lsb, #width SBFIZ Wd, Wn, #lsb, #width SBFX Wd, Wn, #lsb, #width UBFIZ Wd, Wn, #lsb, #width UBFX Wd, Wn, #lsb, #width
Эти инструкции копируют набор битов из второго операнда-регистра в определенное местоположение в первом операнде. Количество копируемых битов задается с помощью четвертого операнда -
#width
.
Третий операнд - #lsb
для инструкций SBFX, UBFX, BFXIL
задает позицию во втором операнде, с которой надо извлечь #width битов, а для
инструкций SBFIZ, UBFIZ, BFI
задает номер бита в первом операнде, с которого происходит вставка копируемых битов .
BFI: извлекает из второго операнда с нулевого байта и вставляет их на определенную позицию в первом операнде, остальные биты в первом операнде остаются неизменными
BFXIL: извлекает из второго операнда с определенной позиции и вставляет их начиная с нулевого байта в первом операнде, остальные биты в первом операнде остаются неизменными
SBFIZ: извлекает из второго операнда с нулевого байта и вставляет их на определенную позицию в первом операнде, остальные старшие биты в первом операнде заполняются знаковым битом, младшие биты - нулями
SBFX: извлекает из второго операнда с определенной позиции и вставляет их начиная с нулевого байта в первом операнде, остальные биты в первом операнде заполняются знаковым битом
UBFIZ: извлекает из второго операнда с нулевого байта и вставляет их на определенную позицию в первом операнде, остальные биты в первом операнде заполняются нулями
UBFX: извлекает из второго операнда с определенной позиции и вставляет их начиная с нулевого байта в первом операнде, остальные биты в первом операнде заполняются нулями
Рассмотрим самую сложную операцию из вышеперечисленных - SBFIZ:
mov x1, #-2 // 0b11111110 mov x0, #0b00011111 // 31 sbfiz x0, x1, #1, #2 // X0 = 0b11111100
Здесь из числа в X1 извлекает 2 бита с начала - 0b11111110 и вставляем из со бита номер 1 в регистр X0.
X0 = 0b00011111 X1 = 0b11111110 ----------- X0 = 0b11111100
Все младшие биты в X0, которые идут до вставленных, заполняются нулями, а старшие биты, которые идут после вставленных, заполняются знаковым битом, который в данном случае равен 1.
Поэтому в X0 в итоге будет число 0b11111100
или -4
Ряд других примеров. BFI
оставляет все биты, кроме вставленных, без изменений:
mov x1, #-2 // 0b11111110 mov x0, #0b0011111 // 13 bfi x0, x1, #1, #2 // X0 = 0b0011101 = 29
UBFIZ
все биты, кроме вставленных, заполняет нулями:
mov x1, #-2 // 0b11111110 mov x0, #0b0011111 // 13 ubfiz x0, x1, #1, #2 // X0 = 0b00000100 = 4