“At the end of the day, we must go forward with hope and not backward by fear and division.” – Jesse Jackson.
It often surprises me how many people believe that “ARM doesn’t do division” or “ARM cores don’t have divide hardware”. Of course, that used to be the case – up until the launch of the Cortex brand in 2004, ARM cores simply didn’t have hardware support for division operations.
Well, here’s the official answer...
Support for the SDIV/UDIV instructions is mandatory in ARMv7-M and for the Thumb instruction set in ARMv7-R. It is optional for the ARM instruction set in ARMv7-R. It is optional in ARMv7-A and, if supported, may be in the Thumb instruction set only or in both Thumb and ARM. In ARMv7-A with the Virtualization Extensions, it is mandatory in Thumb and ARM.
Confused! Well, if you want to know whether your particular core supports these instructions, there is a handy register to check. On ARMv7-A and ARMv7-R cores, the Instruction Set Attribute Register (ID_ISAR0) contains a field called “Divide_instrs” (bits 27:24) which takes the following values:
Divide_instrs”
0000 – Not implemented 0001 – SDIV/UDIV in Thumb instruction set 0010 – SDIV/UDIV in both ARM and Thumb instruction sets
You can find more information in the Architecture Reference Manuals.
The following table shows the status of hardware divide support for all current ARM cores.
The syntax of the instructions is simple enough:
SDIV Rd, Rn, Rm ; Rd = Rn / Rm
The only real wrinkle you need to be aware of is the handling of division by zero. Again, the behavior varies by architecture.
ARMv7-A - divide by zero always returns a zero result.
ARMv7-R - the SCTLR.DZ bit controls whether you get a zero result or a Undefined Instruction exception when you attempt to divide by zero (the default is to return zero).
SCTLR.DZ
ARMv7-M - the CCR.DIV_0_TRP bit controls whether an exception is generated. If this occurs, it will cause a UsageFault and the UFSR.DIVBYZERO bit will indicate the reason for the fault.
CCR.DIV_0_TRP
UFSR.DIVBYZERO
Note that none of the divide instructions, in any of the architectures, affect the condition code flags. All can be made conditional: in ARM state, via the condition code field and in Thumb state via the IT instruction.
So, many ARM cores do support hardware divide these days. But there are still some which don’t. So we should consider what happens there.
In the general case, the compiler will use a run-time library routine for division and you should regard this as “slow”. The ARM tools do provide two versions of the library routine, one of which is labelled “real-time” and is guaranteed to return in fewer than 45 cycles every time. It will be faster for larger quotients but slower for typical quotients so should be used in applications which require a more deterministic division performance.
The compiler will, however, do its best to provide the best division performance it can. In the case of division by a compile-time constant, it will use shifts where possible to divide by power of two, for instance. For other constants, it will use an inline long multiplication sequence to calculate an integer result. For example, here is the sequence it will use for division by ten.
LDR r0, =0xCCCCCCCD UMULL r2, r1, r0, r1 MOV r1, r1, LSR #3
The constant used is a fixed-point binary representation of 1/10. The final shift removes the fractional part of the result to leave an integer.
And don’t forget that the module (%) operator requires a division to work out the remainder, so is really a “divide in disguise”. A common requirement is to increment a counter and wrap it a limit value. Programmers often use a module to do this. The code below shows that a simple test-and-reset construct is much more efficient.
count = (count + 1) % 60;
ADD r1, r0, #1
MOV r0, #0x3c
BL __aeabi_idiv
MOV r0, r1
if (++count >= 60)
count = 0;
ADD r0, r0, #1
CMP r0, #0x3c
MOVCS r0, #0
So far, we have only discussed integer arithmetic. Many applications running on ARM platforms require floating point support.
Many ARM cores support floating point hardware as an option. This applies across the range from the Cortex-M4 microcontroller to the Cortex-R and Cortex-A cores. In many cases, the support is optional so you should check documentation to find out what is supported in your device.
Be careful though and check carefully. The VFP architecture supports single and double precision floating point, including divide operations. The NEON architecture (the two are often implemented together and share a register bank) only supports single precision floating point and doesn’t support division. In these cases, a runtime library would he used.
[CTAToken URL = "https://developer.arm.com/products/processors" target="_blank" text="Learn more about Arm cores" class ="green"]
Thanks for the comment, Pete. Good point which extends to an area I didn't want to get in to in a first pass. It would be good to see an example of you to use those instructions to implement an iterative division operation.