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

发布于 2024-09-16 16:05:41 字数 911 浏览 12 评论 0原文

这是(AFAIK)这个一般主题。

情况是这样的:

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

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

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

代数、(V810)汇编和伪代码都可以。我将从 C 调用代码。

提前致谢!

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

This is (AFAIK) a specific question within this general topic.

Here's the situation:

I have an embedded system (a video game console) based on a 32-bit RISC microcontroller (a variant of NEC's V810). I want to write a fixed-point math library. I read this article, but the accompanying source code is written in 386 assembly, so it's neither directly usable nor easily modifiable.

The V810 has built-in integer multiply/divide, but I want to use the 18.14 format mentioned in the above article. This requires dividing a 64-bit int by a 32-bit int, and the V810 only does (signed or unsigned) 32-bit/32-bit division (which produces a 32-bit quotient and a 32-bit remainder).

So, my question is: how do I simulate a 64-bit/32-bit divide with a 32-bit/32-bit one (to allow for the pre-shifting of the dividend)? Or, to look at the problem from another way, what's the best way to divide an 18.14 fixed-point by another using standard 32-bit arithmetic/logic operations? ("best" meaning fastest, smallest, or both).

Algebra, (V810) assembly, and pseudo-code are all fine. I will be calling the code from C.

Thanks in advance!

EDIT: Somehow I missed this question... However, it will still need some modification to be super-efficient (it has to be faster than the floating-point div provided by the v810, though it may already be...), so feel free to do my work for me in exchange for reputation points ;) (and credit in my library documentation, of course).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

纵情客 2024-09-23 16:05:41

GCC 为许多处理器提供了这样的例程,名为 _divdi3(通常使用通用的 divmod 调用来实现)。 这是一个。一些 Unix 内核也有一个实现,例如 FreeBSD

GCC has such a routine for many processors, named _divdi3 (usually implemented using a common divmod call). Here's one. Some Unix kernels have an implementation too, e.g. FreeBSD.

李白 2024-09-23 16:05:41

如果您的被除数是无符号 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

If your dividend is unsigned 64 bits, your divisor is unsigned 32 bits, the architecture is i386 (x86), the div assembly instruction can help you with some preparation:

#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
}

If the line above with __udivdi3 doesn't compile for you, use the __div64_32 function from the Linux kernel: https://github.com/torvalds/linux/blob/master/lib/div64.c

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文