Search code examples
assemblyarmbit-manipulationkeil

How to determine if there exactly two different bits?


I'm new to assembly language, and trying to check if there are two diff bits.The original binary number is 1111 1111,and I wanna check if there are exactly two bits are 0 in first four bits like 1010 1111. And I tried:

  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

Then check the value of r2. Is there an easier way to address this issue?Thanks!


Solution

  • The key idea for the following algorithm is to use the operation a & a - 1 which clears the least significant set bit in a word. We perform this operation twice. After the first time, we want a nonzero result (so at least 2 bits had been set originally) and after the second time, we want a zero result (so at most 2 bits had been set originally). Recall that we have four bits in total, so two clear bits means that two bits have been set.

    Code looks like this:

            @ 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
    

    An alternative option is to use a look up table for the 16 possible combinations. As memory is usually quite fast on a micro controller, this might be a good idea:

    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
    

    Now as a further improvement, this look up table can be implemented as a bit vector:

    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