ARM THUMB2 function to compare to a number of values

986 views Asked by At

I am pretty new to ARM and am looking to compare a value in a register to a selection of known hex values. At the moment I am doing this by using individual CMP instructions so the code looks like this:

;stuff

CMP r2, #0x41

CMP r2, #0x45

CMP r2, #0x49

etc...

clearly this gets pretty cumbersome after a while and I'm thinking there must a way to compare the value in r2 to a number of hex values all at once.

Aplogies for the newbie question, thanks for the help in advance.

1

There are 1 answers

1
artless noise On

Generally, you look at the valid value range.

  1. Check the value is in range.
  2. Subtract the lowest value from register.
  3. Use modified value as array index; array may have a value key or just be a yes/no.

Step 2,3 are only needed if some values in the range are not valid and the array should be fairly densely pack, which for your two digit hex should be the case.

  # Range check (step 1)
  cmp r2, #hi_val
  bhi out_of_range
  cmp r2, #low_val         ; optimized version is subs r2, r2, #low_val
  blo out_of_range

  # Adjust value (step 2)
  sub r2, r2, #low_val     ; removed in optimized version.

  # Get check from array (step 3)
  adr r0, key_array
  ldrb r0, [r0, r2]  ; base of array + adjusted value.
  bx   lr            ; return w. result in r0.

# Handle not in range.
out_of_range:
  mov  r0, #-1
  bx   lr            ; use 0xffffffff for out of range.

# This is a constant array included with the code.
key_array:
  .byte 1, 1, 0, 1, 1, 1, 0, 0, 1, 1 # etc.

Obviously, your key_array must be changed to be valid with your use case. The condition codes will change slightly for signed and unsigned values.

If key_array is all ones for the binary case, then steps two and three are just return 1;. If the low_val is zero, then you don't need to subtract (or do a low range check). The key_array should be of size hi_val - low_val + 1 or your range check logic can change.

This mechanism is used for many 'ctype' functions such as ispunct, but you may store up to eight values in a byte and use a bit mask to get the one you are interested in. It is also easy to implement in 'C' and use a compiler. It is possible to use only one register (R0 is EABI compatible function) but then the error handling is also intermixed and less clear.