Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Math 如何使用32位除法指令执行64位除法?_Math_Assembly_Cpu Architecture_Fixed Point_Integer Division - Fatal编程技术网

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

Math 如何使用32位除法指令执行64位除法?,math,assembly,cpu-architecture,fixed-point,integer-division,Math,Assembly,Cpu Architecture,Fixed Point,Integer Division,这是一个具体的问题 情况如下: 我有一个基于32位RISC微控制器(NEC V810的变体)的嵌入式系统(视频游戏机)。我想写一个定点数学库。我读过,但附带的源代码是用386汇编编写的,因此既不能直接使用,也不容易修改 V810具有内置的整数乘法/除法,但我想使用上述文章中提到的18.14格式。这需要将64位整数除以32位整数,V810只进行(有符号或无符号)32位/32位除法(产生32位商和32位余数) 所以,我的问题是:如何模拟64位/32位除法和32位/32位除法(以允许红利的预移位)?或

这是一个具体的问题

情况如下:

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

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

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

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

提前谢谢


编辑:不知怎的,我错过了。。。但是,它仍然需要一些修改才能变得超级高效(它必须比v810提供的浮点div更快,尽管它可能已经是…,所以请随时为我做工作以换取信誉点;)(当然,这要归功于我的库文档)。

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

如果您的红利是无符号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
}
#包括
/*返回*a%b,并设置*a=*a\u旧/b*/
uint32_t uint64车道(uint64_t*a、uint32_t b){
#ifdef _i386 _/*u64/u32分区,带有少量i386机器代码*/
uint32_t upper=((uint32_t*)a)[1],r;
((uint32_t*)a)[1]=0;
如果(上限>=b){
((uint32_t*)a)[1]=上/b;
上限%=b;
}
__asm_uuuu(“divl%2”):“=a”((uint32_t*)a)[0]),“=d”(r):
"rm(b),"0(((uint32_t*)a[0],"1(上);;
返回r;
#否则
const uint64_t q=*a/b;/*在libgcc中调用u udivdi3*/
const uint32_t r=*a-b*q;/*`r=*a%b'将使用u umoddi3*/
*a=q;
返回r;
#恩迪夫
}

如果上面带有
\uuu udivdi3
的那行代码没有为您编译,请使用Linux内核中的
\uu div64\u 32
函数:

这似乎正是我所需要的。感谢您链接到相关代码!顺便说一句,我使用的是GCC,但我使用的是newlib,它不包括这些东西。