Sunday, 28 July 2013

Generating processor-specific code from a source file

There are many ARM cores as described at Wikipedia. The processors get more complex as they evolve and occasionally new instructions are introduced. One instance is the rev instruction which will reverse the bytes in a word e.g. for converting big-endian numbers to little-endian and vice versa.

In my Sheeva Plug there is a version 5TE processor (which does not support this instruction); my Raspberry Pi has a version 6 processor (which does).

I would like to keep my code in one source file, and dynamically assemble the optimum code for the processor upon which it was built.

We can use the macro assembler of the GNU assembler to achieve this.

.if ARCH >= 6
 rev r0, r0
.else
 and r2, r0, #0xff000000 @ load the top 2 bytes to r2
 and r3, r0, #0x00ff0000 @ load the next 2 bytes to r3
 and r4, r0, #0x0000ff00 @ load the next 2 bytes to r4
 and r5, r0, #0x000000ff @ load the bottom 2 bytes to r5
 mov r0, r2, lsr #24  @ shift r2 bytes to bottom and store to r0
 orr r0, r3, lsr #8  @ or the remaining shifted data
 orr r0, r4, lsl #8
 orr r0, r5, lsl #24
.endif

We can interrogate the machine at build time by looking inside /proc/cpuinfo via

cat /proc/cpuinfo | grep ^Processor which gives :

  • On A SheevaPlug : Processor : Feroceon 88FR131 rev 1 (v5l)
  • On A Raspberry Pi : Processor : ARMv6-compatible processor rev 7 (v6l)

And then we pull the appropriate number within the Makefile and then we can build via make endian using the following Makefile

AS      := /usr/bin/as
LD      := /usr/bin/ld

ASOPTS  := -gstabs

ARCH = $(shell sed -ne 's/^Processor\s*:.*(v\([0-9]\)l)/\1/p' /proc/cpuinfo)

endian: endian.s
        echo ARCH is $(ARCH)
        $(AS) $(ASOPTS) --defsym ARCH=$(ARCH) -march=armv$(ARCH) -o $@.o $^
        $(LD) -o $@ $@.o

No comments:

Post a Comment