Showing changes from revision #0 to #1:
Added | Removed | Changed
This guide exists to help programmers update their code to run correctly on ARMv7 (and ARMv6) processors. This guide only covers differences between ARMv5 and ARMv6/v7 – i.e. it is assumed that your code is already 32bit compatible and runs correctly on an Iyonix (and without the use of Aemulor!).
If a program is written in plain C, chances are a simple recompilation of the code is all that’s needed.
For users of Norcroft (aka Acorn/Castle C/C++), you need to use the -memaccess option to disable the use of unaligned loads/stores.
-memaccess -L22-S22-L41
The above will produce code which is compatible with all ARM architectures. Norcroft version X.XX and above use this option by default; if you wish to upgrade you can buy the updated compiler from the ROOL store
If you don’t require RiscPC compatibility, you can change ‘-L22-S22’ to ‘+L22+S22’ to enable the use of halfword loads/stores (note you will also need to use the appropriate -cpu option to enable use of the LDRH/STRH instructions).
GCC version 4.1.1 release 2 produces compatible code by default, and is supplied with fully compatible libraries. So if you are using a version of GCC older than the above, it is highly recommended that you visit the RISC OS GCC website and upgrade to the latest
Although GCC 4.1.1 release 1 did produce compatible code, some of the libraries it was supplied with contained hand-crafted assembler that was not compatible with ARMv6/v7. GCC versions 2 and 3 are known to produce incompatible code by default, and at present there is no known way of forcing them to produce compatible code.
There are several differences between ARMv7 and ARMv5 which can cause hand-crafted assembler to fail or malfunction. These issues are listed below.
For ARMv5 and below, the bottom two bits of the source/destination address were always ignored and treated as zero.
For ARMv7 and above, an abort will be raised if the source/destination address is not word-aligned. The abort will occur regardless of the alignment exceptions setting.
For ARMv6, the behaviour is configurable via the system control register – but for maximum compatibility your code should assume ARMv7 behaviour.
For ARMv5 and below, this has the behaviour of a “rotated load”. The data is loaded from a word-aligned address, and then rotated by the number of bytes specified by the bottom two bits of the original address. I.e., for “LDR R1,[R0]”, the behaviour is as follows:
BIC temp,R0,#3 LDR R1,[temp] AND temp,R0,#3 MOV temp,temp,LSL #3 MOV R1,R1,ROR temp
For ARMv7 and above, this has the behaviour of a “sequential load” – four bytes are loaded from sequential locations in memory. I.e., for “LDR R1,[R0]”, the behaviour is as follows:
LDRB R1,[R0] LDRB temp,[R0,#1] ORR R1,R1,temp,LSL #8 LDRB temp,[R0,#2] ORR R1,R1,temp,LSL #16 LDRB temp,[R0,#3] ORR R1,R1,temp,LSL #24
For ARMv6, the behaviour is again configurable via the system control register.
The important thing to realise is that for any particular unaligned load, the bottom N bytes of the data will be correct, while the top 3-N bytes will be “incorrect”. This has caused problems with C compilers, where halfword loads were typically implemented using the following psuedocode:
LDR R1,[R0 EOR #2] MOV R1,R1,(LSR|ASR) #16
This will produce different results in ARMv5 and ARMv7, and could easily lead to unexpected data corruption. This is why alignment exceptions are currently turned on by default for versions of RISC OS running on ARMv6/v7.
Thus, the recommendation is to avoid the use of unaligned LDRs when running on ARMv6/v7.
On ARMv5 and below, the bottom two bits of the destination address are ignored and treated as zero.
On ARMv7 and above, STR performs a “sequential write” – i.e. writing bytes to sequential memory locations using the same addressing scheme as LDR.
For ARMv6, the behaviour is again configurable via the system control register.
Due to the differences in behaviour, and the use of alignment exceptions by default on ARMv6/v7, it is recommended that unaligned STRs are avoided when running on ARMv6/v7.
On ARMv6 and below, a non-halfword aligned LDRH/STRH has unpredictable behaviour.
On ARMv7 and above, non-halfword aligned LDRH/STRH performs a sequential load/store, as per LDR/STR.
Due to the differences in behaviour, and the use of alignment exceptions by default on ARMv6/v7, it is recommended that unaligned LDRH/STRH is avoided when running on all architecture versions.
Other, more exotic multi-byte memory access instructions (LDRD, STRD, LDC, STC, LDRT, STRT, etc.) have had their behaviour changed as well. However, since alignment exceptions are likely to be turned on, it is recommended that you avoid using unaligned loads/stores of any kind unless your code is certain that it will work in the intended manner.
On all ARM processors running in 32bit mode, if a MOVS pc, lr style instruction is executed from user mode (or from the little-used system mode), then it has unpredictable behaviour. So if your supposedly 32bit-compatible code contains a MOVS pc, lr style instruction that gets executed from the USR32 or SYS32 processor mode then you are a bad coder and should punish yourself appropriately.
Unfortunately, not all unpredictable behaviours are created equal – experience suggests that MOVS pc, lr behaves “correctly” on an IOP321 (i.e. Iyonix), but fails on OMAP3, causing code which was otherwise believed to be 32bit compatible to fail.
TODO?
h2(#alignment%20exceptions). Alignment Exceptions
Alignment exceptions (referred to as alignment faults in the ARM ARM) are a feature available in ARMv6 and above. If alignment faults are enabled, any improperly aligned memory access (i.e. loading a word from a 1, 2 or 3 byte offset, or loading a halfword from a byte offset) will trigger an alignment fault. At present RISC OS will report this with the standard “Abort on data transfer” message, so use of the Debugger module to examine the code and registers is advised.
Note that the OMAP3 build of RISC OS currently has alignment exceptions enabled by default. This is to help track down code which relies on ARMv6/v7-incompatible unaligned LDR/STR behaviour. It is unknown when, or if, alignment exceptions will be switched back to the “off” state, so it is advised that you modify your code accordingly.
For testing purposes only, the below BASIC program can be used to turn alignment exceptions off:
DIM code% 256 P%=code% [ OPT 0 SWI "OS_EnterOS" MRC CP15,0,R0,C1,C0,0 BIC R0,R0,#2 MCR CP15,0,R0,C1,C0,0 MSR CPSR_c,#&10 MOV R0,R0 MOV PC,R14 ] CALL code%
The same program, but with an ORR instruction isntead of BIC, can be used to turn alignment exceptions back on again.
For much more detailed information about the differences between ARM architectures, it is recommended that you consult the ARM Reference Manual (ARMv7-A and ARMv7-R edition). from the ARM website. Currently you are required to register in order to gain access to the document, but registration is free and relatively easy.