Как выполнить 64-разрядное разделение с помощью 32-разрядной инструкции divide?
Это (AFAIK) конкретный вопрос в этой теме.
ситуация такая:
У меня есть встроенная система (консоль для видеоигр) на основе 32-битного микроконтроллера RISC (вариант NEC V810). Я хочу написать математическую библиотеку с фиксированной точкой. Я читаю в этой статье, но сопровождающий исходный код написан в сборке 386, поэтому он не может использоваться напрямую и легко модифицироваться.
V810 имеет встроенный integer multiply / divide, но я хочу использовать формат 18.14, упомянутый в вышеупомянутой статье. Это требует деления 64-битный int на 32-битный тип int, а V810 не только (signed или unsigned) 32-бит/32-бит дивизии (которая производит 32-разрядное частное и 32-разрядный остаток).
Итак, мой вопрос: как смоделировать 64-битное/32-битное деление с 32-битным/32-битным (чтобы учесть предварительный сдвиг дивиденда)? Или, чтобы взглянуть на проблему с другой стороны, каков наилучший способ разделить фиксированная точка 18.14 другой с использованием стандартных 32-битных арифметических / логических операций? ("лучший" означает самый быстрый, самый маленький или оба).
Алгебра, (V810) сборка и псевдо-код все в порядке. Я буду вызывать код из C.
спасибо заранее!
EDIT: как - то я пропустил этот вопрос... Тем не менее, ему все равно потребуется некоторая модификация, чтобы быть суперэффективным (он должен быть быстрее, чем div с плавающей запятой, предоставляемый v810, хотя он может уже находиться...), поэтому не стесняйтесь делать мою работу за меня в обмен на очки репутации;) (и кредит в моей библиотечной документации, конечно).
2 ответов
если ваш дивиденд без знака 64 бита, ваш делитель без знака 32 бита, архитектура i386 (x86),div
инструкция по сборке может помочь вам с некоторой подготовкой:
#include <stdint.h>
/* Returns *a % b, and sets *a = *a_old / b; */
uint32_t UInt64DivAndGetMod(uint64_t *a, uint32_t b) {
#ifdef __i386__ /* u64 / u32 division with little i386 machine code. */
uint32_t upper = ((uint32_t*)a)[1], r;
((uint32_t*)a)[1] = 0;
if (upper >= b) {
((uint32_t*)a)[1] = upper / b;
upper %= b;
}
__asm__("divl %2" : "=a" (((uint32_t*)a)[0]), "=d" (r) :
"rm" (b), "0" (((uint32_t*)a)[0]), "1" (upper));
return r;
#else
const uint64_t q = *a / b; /* Calls __udivdi3 in libgcc. */
const uint32_t r = *a - b * q; /* `r = *a % b' would use __umoddi3. */
*a = q;
return r;
#endif
}
если строка выше с __udivdi3
не компилируется для вас, используйте __div64_32
функция из ядра Linux:https://github.com/torvalds/linux/blob/master/lib/div64.c