Как сделать целое (подписанное или неподписанное) разделение на ARM?

В частности, я работаю над Cortex-A8 и Cortex-A9. Я знаю, что в некоторых архитектурах нет целочисленного деления, но какой лучший способ сделать это, кроме преобразования в float, divide, convert to integer? Или это действительно лучшее решение?

Ура! знак равно

assembly,arm,integer-division,instruction-set,cortex-a8,

16

Ответов: 5


4 принят

Компилятор обычно включает разделение в своей библиотеке, gcclib, например, я извлек их из gcc и напрямую их использую:

https://github.com/dwelch67/stm32vld/, затем stm32f4d / adventure / gcclib

собирается плавать и обратно, вероятно, не лучшее решение. вы можете попробовать и посмотреть, как быстро ... Это умножается, но может легко сделать это делением:

https://github.com/dwelch67/stm32vld/, затем stm32f4d / float01 / vectors.s

Я не успел хотя бы увидеть, как быстро / медленно. Понял, что я использую выше корекс-м, и вы говорите о корексе-а, разных концах спектра, аналогичных инструкциях по плаванию и материалах gcc lib аналогичны, для коры головного мозга я должен строить для большого пальца, но вы можете так же легко построить для руки. На самом деле с gcc все должно просто работать автоматически, вам не нужно делать это так, как я это делал. Другие компиляторы также не должны делать это так, как я сделал это в приключенческой игре выше.


10

Подразделение по постоянному значению выполняется быстро, выполняя 64-битное умножение и сдвиг-право, например, следующим образом:

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

здесь R1 * 0xA151C331 / 2 ^ (32 + 10) = R1 * 0.00061538461545751488 = R1 / 1624.99999980 делится на 1625. Расчет выполняется следующим образом: 64bitreg (x / N == (x * A) / 2 ^ (32+ n) -> A = 2 ^ (32 + n) / N: R3) = @ Запись r0: числитель (lo) должен быть подписан положительным @ r2: deniminator (den) должен быть отличным от нуля и подписанным отрицательным idiv: lo .req r0; hi .req r1; den.req r2 mov hi, # 0 @ hi = 0 добавляет lo, lo, lo .rept 32 @ повторять 32 раза adcs hi, den, hi, lsl # 1 subcc hi, hi, den adcs lo, lo, lo .endr mov pc, lr @ return @ Exit r0: quotient (lo) @ r1: остаток (hi) * 0xA151C331, то результатом является верхний 32-битный сдвиг вправо на 10:

  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

Вы можете вычислить свои собственные константы из этой формулы:

ARM GNU

выберите наибольшее n, для которого A <2 ^ 32


Некоторые копии-пасты из других мест для целочисленного разделения: в основном, 3 инструкции на бит. С этого веб-сайта, хотя я видел и много других мест. На этом сайте также есть хорошая версия, которая может быть быстрее в целом.

udiv/sdiv

2

Я написал свою собственную процедуру для выполнения беззнакового разделения, поскольку я не мог найти неподписанную версию в Интернете. Мне нужно было разделить 64-битное значение с 32-битным значением, чтобы получить результат 32 бит.

Внутренний цикл не так эффективен, как вышеприведенное решение, но это поддерживает арифметику без знака. Эта процедура выполняет 32-битное деление, если большая часть числителя (hi) меньше знаменателя (den), в противном случае выполняется полное 64-битное деление (hi: lo / den). Результат получается в lo.

.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

Можно добавить дополнительную проверку для граничных условий и мощности 2. Полную информацию можно найти по адресу: http://www.idwiz.co.za/Tips%20and%20Tricks/Divide.htm


0

Я написал следующие функции для udivассемблера. Если у вас нет процессора с sdivподдержкой машины, просто вырезайте первые несколько строк до метки «0:» в любой из функций.

r1

Существуют две функции r0для беззнакового целочисленного деления и r2для целочисленного деления со знаком. Оба они ожидают 64-битного дивиденда (либо подписанного, либо без знака) в r1(высокое слово) и r0(низкое слово) и 32-разрядного делителя r2. Они возвращают частное в r1и остаток в r1, таким образом , вы можете определить их в C headerкачестве externвозвращения 64-разрядного целого числа и маскировать частное и остаток после этого. Ошибка (деление на 0 или переполнение) указывается остатком, имеющим абсолютное значение, большее или равное абсолютному значению делителя. Алгоритм подписанного деления использует различие случаев по признакам как дивиденда, так и делителя; он сначала не преобразуется в положительные целые числа, так как это не будет правильно определять все условия переполнения.

монтаж, рука, целочисленное деление, набор инструкций, Cortex-A8,
Похожие вопросы