如何使用32位除法指令执行64位除法?

时间:2010-08-26 06:01:01

标签: math assembly cpu-architecture fixed-point integer-division

这是(AFAIK)this general topic中的具体问题。

情况如下:

我有一个基于32位RISC微控制器(NEC V810的变体)的嵌入式系统(视频游戏控制台)。我想写一个定点数学库。我读过this article,但随附的源代码是用386汇编编写的,所以它既不能直接使用也不能轻易修改。

V810内置整数乘法/除法,但我想使用上面文章中提到的18.14格式。这需要将64位int除以32位int,而V810仅执行(有符号或无符号)32位/ 32位除法(产生32位商和32位余数)。 / p>

所以,我的问题是:如何使用32位/ 32位分频模拟64位/ 32位除法(允许分红的预移位)?或者,从另一种方式来看问题,使用标准的32位算术/逻辑运算将18.14定点除以另一种定义的最佳方法是什么? (“最好”意味着最快,最小或两者兼而有之。)

代数,(V810)程序集和伪代码都很好。我将从C调用代码。

提前致谢!

编辑:不知怎的,我错过了this question ...但是,它仍然需要一些修改才能超级高效(它必须比v810提供的浮点div更快,尽管它可能已经是...),所以我可以随意为我工作以换取声望点;)(当然,还有我的图书馆文档中的信用)。

2 个答案:

答案 0 :(得分:5)

GCC对许多处理器都有这样的例程,名为_divdi3(通常使用公共的divmod调用实现)。 Here's one。一些Unix内核也有一个实现,例如FreeBSD

答案 1 :(得分:1)

如果你的被除数是无符号的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行无法为您编译,请使用Linux内核中的__div64_32函数:https://github.com/torvalds/linux/blob/master/lib/div64.c