如何在Micropython汇编语言中测试浮点寄存器的符号
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在Micropython汇编语言中测试浮点寄存器的符号相关的知识,希望对你有一定的参考价值。
我正在学习MicroPython的汇编程序(用于PyBoard的ARM Thumb2指令集)。
有没有更快的方法来检查FPU寄存器(s0)的符号(正/负)?
@micropython.asm_thumb
def float_array_abs(r0, r1):
label(LOOP)
vldr(s0, [r0, 0])
vmov(r2, s0) # 1
cmp(r2, 0) # 2
itt(mi) # 3
vneg(s0, s0)
vstr(s0, [r0, 0])
add(r0, 4)
sub(r1, 1)
bgt(LOOP)
这有效,但它似乎不是'正确'的解决方案(不确定r2
的标志总是与s0
的标志相符),我怀疑它必须在不到两个指令中可行。
更新1:
根据评论(谢谢),我进一步提高了代码的速度:
@micropython.asm_thumb
def float_array_abs1(r0, r1):
label(LOOP)
ldr(r2, [r0, 0])
cmp(r2, 0) # this works for some reason
bge(SKIP)
vmov(s0, r2)
vneg(s0, s0)
vstr(s0, [r0, 0]) # this can be skipped if not negative
label(SKIP)
add(r0, 4)
sub(r1, 1)
bgt(LOOP)
但它仍然存在一个问题,这是一种确定FP值符号的可靠方法吗?
这里参考我系统上四个浮点值的字节表示:
-1.0 0xbf800000
-0.0 0x80000000
0.0 0x00000000
1.0 0x3f800000
我想如果这是硬件依赖的那么我不应该依靠它来确定标志......
我认为这可能是“正确”的方式(即适当的FPU比较):
def float_array_abs2(r0, r1):
mov(r2, 0)
vmov(s1, r2)
label(LOOP)
vldr(s0, [r0, 0])
vcmp(s0, s1)
vmrs(APSR_nzcv, FPSCR)
itt(mi)
vneg(s0, s0)
vstr(s0, [r0, 0])
add(r0, 4)
sub(r1, 1)
bgt(LOOP)
但是我计时了,它比上面的代码慢了11%(float_array_abs1
)。因此,如果它是一个可靠的解决方案,那么使用早期的代码会更好。
更新2:
@ Ped7g提出了方法and 0x7FFFFFFF
(见评论)。
我测试了它,它确实有效。这是代码:
@micropython.asm_thumb
def float_array_abs3(r0, r1):
movwt(r3, 0x7FFFFFFF)
label(LOOP)
ldr(r2, [r0, 0])
and_(r2, r3)
str(r2, [r0, 0])
add(r0, 4)
sub(r1, 1)
bgt(LOOP)
更正:它比上面的float_array_abs1
更快。这似乎是最好的解决方案,但它是否健壮?
使用and
将符号位掩码为0对于像Qazxswpoi和float
这样的IEEE 754二进制浮点格式是安全且最佳的。
它会根据需要将-Inf转换为+ Inf。它会将double
转换为-NaN
,但它仍然是NaN。
NaN由全1指数和非零有效数表示。 Inf是全有指数,零有效数。 (+NaN
)
大多数代码都不关心NaN的有效负载或符号,只是它是NaN,所以清除符号位就可以了。
ARM可以使用整数SIMD NEON指令一次执行4个单精度浮点运算。我不知道VFP(非NEON硬件FPU)是否支持AND指令。
相关:https://en.wikipedia.org/wiki/Single-precision_floating-point_format AND也是x86的最佳方式。
顺便说一下,在单独的循环中执行此操作可能会浪费内存带宽。在读取数组的循环中动态执行绝对值可能是最好的,除非您在写入一次后多次读取此数组。至少如果你能在FP寄存器中进行AND操作。加载到AND的整数寄存器然后从整数移动到FP以获得数学指令会很糟糕。
通常,您需要在循环中使用更多的计算强度(对内存中的每个负载执行更多ALU工作)。
以上是关于如何在Micropython汇编语言中测试浮点寄存器的符号的主要内容,如果未能解决你的问题,请参考以下文章