如何在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汇编语言中测试浮点寄存器的符号的主要内容,如果未能解决你的问题,请参考以下文章

汇编浮点指令

MicroPython 如何嵌入汇编-悦德财富

汇编语言debug常用指令整理

如何用汇编语言读取内存值

《逆向分析实战》1.1

如何将浮点常量移入 FP 寄存器?