我正在研究Cortex-A8和Cortex-A9。我知道一些體系結構不是用整數除法,但除了轉換爲浮點數,除法,轉換爲整數之外,最好的方法是什麼?或者這確實是最好的解決方案?如何在ARM上進行整數(有符號或無符號)除法?
乾杯! =)
我正在研究Cortex-A8和Cortex-A9。我知道一些體系結構不是用整數除法,但除了轉換爲浮點數,除法,轉換爲整數之外,最好的方法是什麼?或者這確實是最好的解決方案?如何在ARM上進行整數(有符號或無符號)除法?
乾杯! =)
編譯器通常包括在其庫例如我已經提取他們從GCC除法,gcclib並直接使用它們:
https://github.com/dwelch67/stm32vld/然後stm32f4d /冒險/ gcclib
要浮起並回可能不是最好的解決方案。你可以嘗試一下,看看如何快速的...這是一個乘法,但可以作爲很容易使一個除法:
https://github.com/dwelch67/stm32vld/然後stm32f4d/float01/vectors.s
我沒有時間它雖然看多快/多慢。我明白了我正在使用上面的cortex-m,並且你正在討論一個cortex-a,譜的不同端,類似的浮點指令和gcc lib的東西是類似的,因爲我必須爲拇指創建cortex-m,但是可以就像輕鬆建立手臂一樣。實際上,使用gcc它應該都是自動工作的,你不需要像我這樣做。其他編譯器也不應該像我在上面的冒險遊戲中那樣做。
從其他地方的一些複製麪食整數除法: 基本上,每位3指令。來自this的網站,儘管我也見過很多其他地方。 This網站也有一個很好的版本,可能會更快一般。
@ Entry r0: numerator (lo) must be signed positive
@ r2: deniminator (den) must be non-zero and signed negative
idiv:
lo .req r0; hi .req r1; den .req r2
mov hi, #0 @ hi = 0
adds lo, lo, lo
.rept 32 @ repeat 32 times
adcs hi, den, hi, lsl #1
subcc hi, hi, den
adcs lo, lo, lo
.endr
mov pc, lr @ return
@ Exit r0: quotient (lo)
@ r1: remainder (hi)
這是每個位3個指令,但不是每個位3個週期。每個步驟中的所有指令都立即取決於前一個的標誌設置,這意味着取決於內核的結果延遲了3-4個週期。這可能需要每個步驟9-12個週期,總共約360個週期。 –
聽起來正確。如果可以擺動它,反向乘法固定點總是更好的選擇。 –
我寫了自己的例程來執行未簽名的部門,因爲我無法在網上找到未簽名的版本。我需要用一個32位的值來分割一個64位的值來得到一個32位的結果。
內部循環不如上面提供的已簽名解決方案那樣高效,但是它支持無符號算術。如果分子(hi)的高部分小於分母(den),則該例程執行32位除法,否則執行完整的64位除法(hi:lo/den)。結果是lo。
cmp hi, den // if hi < den do 32 bits, else 64 bits
bpl do64bits
REPT 32
adds lo, lo, lo // shift numerator through carry
adcs hi, hi, hi
subscc work, hi, den // if carry not set, compare
subcs hi, hi, den // if carry set, subtract
addcs lo, lo, #1 // if carry set, and 1 to quotient
ENDR
mov r0, lo // move result into R0
mov pc, lr // return
do64bits:
mov top, #0
REPT 64
adds lo, lo, lo // shift numerator through carry
adcs hi, hi, hi
adcs top, top, top
subscc work, top, den // if carry not set, compare
subcs top, top, den // if carry set, subtract
addcs lo, lo, #1 // if carry set, and 1 to quotient
ENDR
mov r0, lo // move result into R0
mov pc, lr // return
可以額外檢查邊界條件和2的冪。可以在http://www.idwiz.co.za/Tips%20and%20Tricks/Divide.htm
除以一個恆定值可以找到全部細節是做一個64位乘法和右移,例如,像這樣快速完成:
LDR R3, =0xA151C331
UMULL R3, R2, R1, R3
MOV R0, R2,LSR#10
這裏R1是1625分。64bitreg(R2:R3)= R1 * 0xA151C331,那麼結果是上側的32位由10向右移動: 計算是這樣進行
R1*0xA151C331/2^(32+10) = R1*0.00061538461545751488 = R1/1624.99999980
可以從這個公式計算自己的常量:
x/N == (x*A)/2^(32+n) --> A = 2^(32+n)/N
選擇最大的n箇中,其中A < 2^32
這裏有舍入錯誤。對於N = 7的無符號32位除法,我們有n = 2和A = 2454267026.28 ...如果我們取整的A值減小,那麼對於「4294967292/7」,結果太小。如果我們把它四捨五入,那麼它會給「4294967291/7」帶來太大的結果。這隻有在A的精確值的小數部分小於0.5時纔會發生,所以它對於N的大約一半的值(比如3,5或1625)很好。 –
我寫了下面功能的ARM GNU
彙編。如果您沒有支持udiv/sdiv
機器的CPU,只需在任一功能中刪除前幾行直到「0:」標籤。
.arm
.cpu cortex-a7
.syntax unified
.type udiv,%function
.globl udiv
udiv: tst r1,r1
bne 0f
udiv r3,r0,r2
mls r1,r2,r3,r0
mov r0,r3
bx lr
0: cmp r1,r2
movhs r1,r2
bxhs lr
mvn r3,0
1: adds r0,r0
adcs r1,r1
cmpcc r1,r2
subcs r1,r2
orrcs r0,1
lsls r3,1
bne 1b
bx lr
.size udiv,.-udiv
.type sdiv,%function
.globl sdiv
sdiv: teq r1,r0,ASR 31
bne 0f
sdiv r3,r0,r2
mls r1,r2,r3,r0
mov r0,r3
bx lr
0: mov r3,2
adds r0,r0
and r3,r3,r1,LSR 30
adcs r1,r1
orr r3,r3,r2,LSR 31
movvs r1,r2
ldrvc pc,[pc,r3,LSL 2]
bx lr
.int 1f
.int 3f
.int 5f
.int 11f
1: cmp r1,r2
movge r1,r2
bxge lr
mvn r3,1
2: adds r0,r0
adcs r1,r1
cmpvc r1,r2
subge r1,r2
orrge r0,1
lsls r3,1
bne 2b
bx lr
3: cmn r1,r2
movge r1,r2
bxge lr
mvn r3,1
4: adds r0,r0
adcs r1,r1
cmnvc r1,r2
addge r1,r2
orrge r0,1
lsls r3,1
bne 4b
rsb r0,0
bx lr
5: cmn r1,r2
blt 6f
tsteq r0,r0
bne 7f
6: mov r1,r2
bx lr
7: mvn r3,1
8: adds r0,r0
adcs r1,r1
cmnvc r1,r2
blt 9f
tsteq r0,r3
bne 10f
9: add r1,r2
orr r0,1
10: lsls r3,1
bne 8b
rsb r0,0
bx lr
11: cmp r1,r2
blt 12f
tsteq r0,r0
bne 13f
12: mov r1,r2
bx lr
13: mvn r3,1
14: adds r0,r0
adcs r1,r1
cmpvc r1,r2
blt 15f
tsteq r0,r3
bne 16f
15: sub r1,r2
orr r0,1
16: lsls r3,1
bne 14b
bx lr
有兩個功能,udiv
無符號整數除法和sdiv
有符號整數除法。他們都希望在r1
(高字)和r0
(低字)中有一個64位的分紅(無論是有符號還是無符號),並且在r2
中有一個32位的分頻。它們返回r0
中的商和r1
中的餘數,因此您可以在C header
中將它們定義爲extern
,返回64位整數並在之後屏蔽商和餘數。一個錯誤(除以0或溢出)由絕對值大於或等於除數絕對值的餘數表示。有符號劃分算法通過分紅和除數的符號來區分大小寫;它不會首先轉換爲正整數,因爲它不會正確檢測所有溢出條件。
當然,即使硬件中不存在,編譯器也會支持軟件模式下的整數除法。我懷疑那些高規格芯片沒有整數除法。我認爲ATMega(像Arduino)缺乏它。 – leppie
ARM上的整數除法的彙編指令不存在。 – Phonon
可以將其轉換爲浮點或用展開的3操作碼模式進行手動分割。 –