Как определить, существуют ли ровно два разных бита?

#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. если требуется битовая позиция каждого нуля, это может быть закодировано в двух половинах байта в поисковой таблице.