如何确定是否恰好有两个不同的位?

How to determine if there exactly two different bits?

我是汇编语言的新手,正在尝试检查是否有两个差异 bits.The 原始二进制数是 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的值。有没有更简单的方法来解决这个问题?谢谢!

以下算法的关键思想是使用操作 a & 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 & (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 & (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 种可能的组合使用查找 table。由于微控制器上的内存通常非常快,这可能是个好主意:

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

现在作为进一步的改进,这个查找 table 可以实现为一个位向量:

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