#assembly #arm #bit-manipulation #keil
Вопрос:
Я новичок в языке ассемблера и пытаюсь проверить, есть ли два разных бита.Исходное двоичное число равно 1111 1111
,и я хочу проверить, есть ли ровно два бита 0 в первых четырех битах, например 1010 1111
. И я попытался:
mov r1,#4 ;count for first four bits
mov r2,#0 ;count for diff bit
ldr r4,=0xAF ;the number that need to check
mov r4,r4,lsr #4
count
ldr r3,=0x1
and r3,r4
cmp r3,#1
bne notDiff
add r2,#1
notDiff
mov r4,r4,lsr #1
subs r1,#1
bne toEnd
b count
toEnd
fin b fin
Затем проверьте значение r2
. Есть ли более простой способ решить эту проблему?Спасибо!
Комментарии:
1. На какой процессор вы программируете? В нем есть НЕОН или Гелий?
2. @old_timer Спасибо! Но есть ли способ узнать положение этих нулей одновременно?
3. @old_timer Да, это РУКА. Чтобы представить позицию, я хочу сохранить нуль с более высоким номером в r0, а нижний-в r1
4. @PeterCordes И если это недоступно (OP, к сожалению, не хочет мне говорить), вы можете выполнить
x | (x 1)
операцию дважды, чтобы установить минимум два очищенных бита, а затем проверить, равен ли результат-1
и предыдущее число не было равно-1
. (еще лучше, дополните сначала и сделайтеx amp; (x-1)
так, чтобы вы могли избежать некоторыхcmp
инструкций).5. @XYWnot Хорошо. Это чип ARM7TDMI. Вы программируете в режиме ARM или в режиме большого пальца?
Ответ №1:
Ключевая идея следующего алгоритма состоит в том, чтобы использовать операцию a amp; a - 1
, которая удаляет наименее значимый бит набора в слове. Мы выполняем эту операцию дважды. После первого раза мы хотим получить ненулевой результат (чтобы изначально было установлено не менее 2 битов), а после второго раза мы хотим получить нулевой результат (чтобы изначально было установлено не более 2 битов). Напомним, что у нас всего четыре бита, поэтому два четких бита означают, что два бита были установлены.
Код выглядит так:
@ assumes input in R4
@ increments R2 if there exactly two bits are set
count: and r4, r4, #0xf0 @ clear out all but the four bits we want to check
sub r0, r4, #1 @ r0 = r4 - 1
ands r0, r4, r0 @ r0 = r4 amp; (r4 - 1)
bxeq lr @ if r0 == 0, we had 0 or 1 bit set: ignore
sub r1, r0, #1 @ r1 = r0 - 1
tst r1, r0 @ r0 amp; (r0 - 1)
addeq r2, r2, #1 @ if the result was zero, we had 2 bits set
@ so go ahead and increment r2
bx lr
Альтернативным вариантом является использование таблицы поиска для 16 возможных комбинаций. Поскольку память на микроконтроллере обычно работает довольно быстро, это может быть хорошей идеей:
count2: adr r0, #lut @ load look up table address
ldrb r0, [r0, r4, lsr #4] @ fetch result from look up table
add r2, r2, r0 @ add result to R2
bx lr
lut: .byte 0, 0, 0, 1
.byte 0, 1, 1, 0
.byte 0, 1, 1, 0
.byte 1, 0, 0, 0
Теперь в качестве дальнейшего улучшения эта таблица поиска может быть реализована в виде битового вектора:
count3: ldr r1, =0x16680000 @ load look up table
mov r0, r4, lsr #4 @ compute look up table index
movs r0, r1, lsl r0 @ move desired LUT bit into N flag
addmi r2, r2, #1 @ increment r2 if N bit set
bx lr
Комментарии:
1. если требуется битовая позиция каждого нуля, это может быть закодировано в двух половинах байта в поисковой таблице.