Domanda

Sto lavorando su Cortex-A8 e Cortex-A9 in particolare. So che alcune architetture non sono dotati di divisione intera, ma qual è il modo migliore per farlo diverso convertito al galleggiante, dividere, convertito intero? O è che in effetti la soluzione migliore?

Cheers! =)

È stato utile?

Soluzione

Il compilatore comprende normalmente una frattura nella sua libreria, gcclib per esempio li ho estratto da gcc e utilizzarli direttamente:

https://github.com/dwelch67/stm32vld/ poi stm32f4d / avventura / gcclib

andare a galleggiare e ritorno non è probabilmente la soluzione migliore. si può provare e vedere come veloce è ... Questo è un moltiplicano, ma potrebbe facilmente rendere un divario:

https://github.com/dwelch67/stm32vld/ poi stm32f4d / float01 / vettori. s

I tempo non ha ancora, però per vedere quanto veloce / lento. Capito Sto usando una corteccia m sopra e si sta parlando di una corteccia-a, diverse le estremità dello spettro, le istruzioni galleggiante simili e la roba gcc lib è simile, per la corteccia-m devo costruire per pollice, ma si può altrettanto facilmente costruire per il braccio. In realtà con gcc dovrebbe tutto solo lavorare automagicamente non dovreste aver bisogno di farlo nel modo in cui ho fatto. Altri compilatori così non dovreste aver bisogno di farlo nel modo che ho fatto nel gioco di avventura di cui sopra.

Altri suggerimenti

La divisione per un valore costante è fatto rapidamente facendo un 64bit-moltiplicano e lo spostamento a destra, per esempio, in questo modo:

LDR     R3, =0xA151C331
UMULL   R3, R2, R1, R3
MOV     R0, R2,LSR#10

qui R1 viene diviso per 1625. Il calcolo viene effettuato in questo modo: 64bitreg (R2: R3) = R1 * 0xA151C331, allora il risultato è il 32bit superiore destro spostata di 10:

R1*0xA151C331/2^(32+10) = R1*0.00061538461545751488 = R1/1624.99999980

È possibile calcolare le proprie costanti da questa formula:

x / N ==  (x*A)/2^(32+n)   -->       A = 2^(32+n)/N

selezionare il più grande n, per cui A <2 ^ 32

Alcuni copia-paste da altrove per una divisione intera: Fondamentalmente, 3 Istruzioni per bit. Da questo sito , anche se ho visto molti altri posti. Questo sito ha anche una versione bella che può essere più veloce in generale .


@ 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)

ho scritto la mia routine per eseguire una divisione senza segno come non ho potuto trovare una versione senza segno sul web. Ho bisogno di dividere un valore a 64 bit con un valore di 32 bit per ottenere un risultato a 32 bit.

Il ciclo interno non è così efficiente come la soluzione firmata riportata, ma questo non supporto aritmetica senza segno. Questa routine esegue una divisione 32 bit se la parte alta del numeratore (hi) è minore del denominatore (den), altrimenti viene eseguita una divisione completa a 64 bit (hi: lo / den). Il risultato è a 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

controllo extra per condizioni al contorno e potenza di 2 può essere aggiunto. I dettagli completi sono disponibili all'indirizzo http://www.idwiz.co.za /Tips%20and%20Tricks/Divide.htm

ho scritto le seguenti funzioni per l'assemblatore ARM GNU. Se non si dispone di una CPU con supporto della macchina udiv/sdiv, basta tagliare le prime righe fino alla "0". Label sia in funzione

.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

Ci sono due funzioni, udiv per la divisione intero senza segno e sdiv per la divisione intero con segno. Entrambi si aspettano un dividendo a 64 bit (firmato o non firmato) in r1 (alta parola) e r0 (low word), e una a 32 bit divisore r2. Restituiscono il quoziente in r0 e il resto in r1, così si possono definire in C header come extern restituendo un intero a 64 bit e mascherare il quoziente e resto in seguito. Un errore (divisione per 0 o overflow) è indicato da un residuo avente un maggiore valore assoluto o uguale al valore assoluto del divisore. L'algoritmo di divisione firmato utilizza caso distinzione per i segni di entrambi dividendo e divisore; che non si converte in numeri interi positivi prima, dal momento che non consentono di rilevare tutte le condizioni di overflow correttamente.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top