0

How do I Combine an array of four byte into one 32-bit. The first item should go into the most significant nibble of the result. Store the result in the 32-bit variable result.

Input: [LIST] = 0xC, 0x2, 0x6, 0x9 (Each item is a byte, Use DCB to define a variable of type byte)

Output: [RESULT] = 0x0C020609

edit answer:

ADD R1, R0
MOV R1, R1, LSL #8
ADD R0, R0, #8
ADD R1, R0
MOV R1, R1, LSL #8
ADD R0, R0, #8
ADD R1, R0
MOV R1, R1, LSL #8
ADD R0, R0, #8
ADD R1, R0
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • 0x0C0206209 is 36 bits long (32 if I ignore the leading zero) ... but I think it's a typo, you meant `0x0C020609` probably. That's still 32b, not 16b. So in the end should be the result `0xC269`? (would make sense, considering the initial 16bit talk, and "nibble" usage (nibble is 4b)) – Ped7g Sep 12 '16 at 18:57

2 Answers2

1

What you're describing is the same thing as treating 4 contiguous bytes as a 32-bit integer stored in big-endian byte-order.

According to gcc (on the Godbolt compiler explorer), the best way to byte-swap from big-endian to ARM-native endian is with the instruction that ARM provides explicitly for this purpose:

rev   r0, r0 

#include <stdint.h>
#include <endian.h>
#include <string.h>

// type-punning with unions is an alternative to memcpy from a char array to an int
union be_bytes {
  uint32_t be_word;
  char bytes[4];
};

uint32_t be_bytes_to_native( char *array ) {
  union be_bytes tmp;
  memcpy(tmp.bytes, array, 4);   // memcpy since we take a char* arg instead of a union be_bytes * arg.
  //  I *think* (union be_bytes*)array would be safe, but I'm not 100% sure.

  // GNU C and many other compilers guarantee that writing one union member and reading another is safe.  ISO C doesn't, so this technically isn't portable.
  return be32toh(tmp.be_word);   // from endian.h, uses compiler builtins, inline asm, or some C shift and mask instructions.
}

compiles to

be_bytes_to_native:
    ldr     r0, [r0]  @ unaligned
    rev     r0, r0
    bx      lr

Without the REV instruction, @dwelch's answer on Endianness conversion in ARM suggests a 4-instruction sequence for byte-swapping a 32-bit value in ARM:

  eor r3,r1,r1, ror #16
  bic r3,r3,#0x00FF0000
  mov r0,r1,ror #8
  eor r0,r0,r3, lsr #8

Note how this combines use of the barrel shifter with instructions other than MOV. I'm still not sure what ADD R0, R0, #8 (r0 += 8) in your code is supposed to be for.

Community
  • 1
  • 1
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
0
*result* = 0
for each *byte* from *list*:
    shift *result* 4 bits left  ; move previous values to make room for next one
    AND *byte* with mask to keep only lower 4 bits (0x0F)room
    OR *masked byte* to *result* ("add" would work too, as all is masked properly)
done.

About your code after edit:
I'm pretty sure it does something different than you wanted, but I'm not sure which CPU/dialect this is, reminds me a bit of ARM.

If LDR R0,=LIST is fetching all 4 bytes in single go, that's clever.

But then you mask R0 with MSB (so you know endianness of your platform, and this one is first?) and store that in R1 (makes some sense, to extract first byte into R1 into MSB position).

Then you add 4 to R0 (doesn't make any sense to me, destroys last byte value). Then you extract second byte into R1 (overwrite previous value of R1), etc...

Finally you store into R1 and RESULT the fourth byte value + 12 (result = 0x00000015).


BTW, you should compile your code, and debug in some debugger, to see what you did, you will learn much faster that way. Just guessing on the paper, when you have the real HW almost for free? I had to code on paper, because I had access to actual HW only once per week for 3h, so I had barely time to retype the code into computer, run it, watch it crash (I didn't know debugger back then), and I had another week of paper work to figure out what happened, fix it, and try it again...

But today you can simply type it into machine, compile, and step into it instruction by instruction. Can't be easier.

Ped7g
  • 16,236
  • 3
  • 26
  • 63
  • As you edited question into 32 bit word. Then just adjust shifting and masking in my algorithm. (so shift left by 8 bits, and mask by 0xFF, which is not needed, if you fetched only single byte, as byte fits into 0xFF exactly). – Ped7g Sep 12 '16 at 19:17
  • But on Big-endian platform your task doesn't make much sense, as you can simply fetch the 4 bytes as single 32b word from memory and store it into result (the "list" is already forming big-endian 32b word in memory). (UPS, now I see ARM can work also as little-endian, and actually on modern ARM you can switch freely between them, so it depends). – Ped7g Sep 12 '16 at 19:19
  • I think this should do it, I'm still very new to this, so I'm using whatever I was taught currently ADD R1, R0 MOV R1, R1, LSL #8 ADD R0, R0, #8 ADD R1, R0 MOV R1, R1, LSL #8 ADD R0, R0, #8 ADD R1, R0 MOV R1, R1, LSL #8 ADD R0, R0, #8 ADD R1, R0 – Undead Left Click Sep 12 '16 at 19:41