0
votes

Say we have a 32-bit value in a register: r0 = 0x12345678; The task is to get the low half-word part, which is 0x5678 (or alternatively nullify the high half-word). In terms of C code that's equivalent to: r0 = r0 & 0xFFFF;

Limitations: it needs to be done in a single ARM7TDMI instruction without using other registers. This is motivated by the fact that getting the high half is just a right shift like LSR r0, r0, #16.

So far I can do it either in 2 instructions: left shift + right shift, rotate + shift; or by using an additional register containing a mask 0xFFFF and AND-ing.

On ARM7TDMI it's not possible to just AND with a constant like 0xFFFF, because it doesn't fit into the immediate value scheme.

In addition it looks like that modern ARM-s have "MOVT" which solves it by doing MOVT r0, #0, but ARM7TDMI doesn't have it!

I want to believe that it's possible without MOVT, because it's such a basic thing.

1
What is the context; i.e., move an immediate, a register, or load 16-bit half-word from memory?InfinitelyManic
Notwithstanding "most efficient" for the moment. Is your goal to do something like ldrh r0,=0x12345678, where r0 would receive the lower 16 bits of the literal pool 0x12345678 (not to be confused with a memory address)?InfinitelyManic
The context is that the 32-bit value is already loaded in a register. Now I need to cut the low 16-bit from that first register into a second (or the same) register, i.e. discard the top half somehow. In this example: 0x1234 is junk, and 0x5678 is an informative part. Most efficient in terms of CPU cycles and extra memory usage. Ideally with 1 CPU cycle and no extra memory (no extra registers and no literal pools).battlmonstr
Can you keep 0x0000FFFF in another register that you set up outside a loop?Peter Cordes

1 Answers

3
votes

If someone's implied this can be done in one instruction on ARM7TDMI, they're having you on. The canonical "zero-extend a halfword" sequence from all early ARM documentation is two shifts, as in this example from the ARM7DI datasheet:

4.15.5 Loading a halfword (Little Endian)

LDR      Ra, [Rb,#2]          ; Get halfword to bits 15:0
MOV      Ra,Ra,LSL #16        ; move to top
MOV      Ra,Ra,LSR #16        ; and back to bottom
                              ; use ASR to get sign extended version

What 7TDMI (ARMv4T) added over 7DI (ARMv3) was halfword loads and stores*, so this particular example dies out after that (it would be merely LDRH Ra, [Rb]), but loads are of course only for values already in memory; there is still nothing to zero/sign-extend a register in a single instruction until ARMv6 introduces UXTH/SXTH.

* among many other things which are of no relevance here.