68K汇编中的取模运算

5

我想知道在Motorola 68000汇编中是否有执行模运算的命令/方法?

我想执行d4 mod 1000和d3 mod 100。

目前我正在使用以下公式,但需要多行代码:

如果a mod n,则a - (n * int(a/n))

我已经看到了d0 mod d1的这个公式。

CLR.L D2
MOVE.W D0,D2
DIVU D1,D2
SWAP D2

感谢您的回答。

2
如果你想让程序运行更快,可以查看gcc输出的C函数,找到你需要的功能。它将使用乘法逆元来进行除法计算,在大多数CPU上比除法运算要快得多。在现代x86架构中,通过乘法和移位,再进行一次乘法并从被除数中减去余数,要比使用硬件的“div”指令直接获取余数要快得多。 - Peter Cordes
2
为什么GCC在实现整数除法时使用奇怪的数字乘法?当手写汇编代码时,生成常量的最简单方法是将unsigned foo(unsigned x) { return x/1000; }%放入C编译器中。 - Peter Cordes
2个回答

8

“DIVU”指令可以精准地完成您所需的操作。执行“DIVU”时,目标长字被源字分割。在您的情况下,您写了:

DIVU D1, D2

因此,D2被D1除。在商中,返回两个部分。D2的高位字包含余数(模数),而低位字包含商。这就是为什么通常会看到SWAP d2。这将余数移动到低位字。


非常感谢,这很有启发性。如何清除数据寄存器中的高或低位字? - Dartuso
2
你可以这样做:先执行 CLR.W D2,然后再执行 SWAP D2。这将清除低位字(商),然后执行交换操作。 - David Hoelzer
不要忘记,如果商的大小超出了16位无法容纳的范围,DIVU指令会放弃计算,并在条件码寄存器中标记溢出,此时结果变得不可靠。 - Gunnar Vestergaard

2
  1. 进行除法运算,结果为低16位的商数和高16位的余数
  2. 将商数设置为零,以便在交换余数时它是一个有效的32位值
  3. ...
START
       DIVU  #1000,D4
       CLR.W D4             ; delete quotient
       SWAP  D4             ; modulus from top to bottom 16 bits

       DIVU  #100,D3
       CLR.W D3             ; delete quotient
       SWAP  D3             ; modulus from top to bottom 16 bits

这段代码没有处理结果是否大于#ffff(65535)的情况,需要额外的代码来检查D3/D4是否大于左移16位后的除数。因为模数将是0到99/999之间的数字,所以你可以在交换操作之后使用EXT.W而不是在交换之前使用CLR.W。请注意,EXT会对值进行符号扩展。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接