gpt4 book ai didi

assembly - 如何在汇编中将有符号 8 位字节转换为有符号 16 位整数?

转载 作者:行者123 更新时间:2023-12-02 21:32:45 26 4
gpt4 key购买 nike

使用 Arduino,我必须在 Atmel AVR Assembly 中为我的计算机科学类(class)编写一个函数,将带符号的 8 位字节转换为带符号的 16 位整数。我也不允许使用任何分支指令(但跳过是可以的)。

我知道这是错误的,但这就是我迄今为止所得到的:

.global byteToInt
byteToInt:
sbrc r24, 7
ldi r25, 1
asr r25
ret

有谁知道我如何使这个功能发挥作用?任何帮助将不胜感激!

最佳答案

显然,您需要将 char 的符号位复制到上半部分的每一位。在大多数架构上,最简单的方法是复制一个寄存器并将其算术右移 7。但是 AVR 只有 shift-by-1 instruction。 ,所以我们无法有效地做到这一点。

有条件地将 0 或 -1 存入寄存器的另一个技巧是 subtract-with-borrow从自身寄存器获取0 - C。例如sbc r25,r25

现在我们只需要一种方法来设置进位标志,如果 8 位数字为负数,即当它被视为无符号整数时,如果它 > 127,因为 C 总是基于事物的无符号解释来设置。 AVR 有一个比较立即指令,CPI ,但仅适用于 r16-r31,不适用于低寄存器。此外,它设置的 cflags与我们真正想要的相反,因此我们必须使用另一条指令来反转结果。所以我认为我们最好以另一种方式与寄存器中的值进行比较:

; Most efficient way, I think:
sign_extend:
ldi r25, 127 ; can be hoisted out of loops, and any reg is fine.

cp r25, r24 ; C = (r24 < 0)
sbc r25, r25 ; r25 = (r24 < 0) ? -1 : 0
; result in r25:r24

更好的是,如果您需要在循环中执行此操作,可以将 127 保存在不同的寄存器中。

对于 CPI,您可以这样做:

; slightly worse: only works with r16-r31, and worse in loops
sign_extend:
cpi r24, 127 ; C = (r24 < 128U) = ((signed)r24 >= 0)
sbc r25, r25 ; r25 = (r24>=0) ? -1 : 0
com r25 ; ones-complement negation: 0 : -1

或者,为了避免使用哪个寄存器的限制,请以其他方式进行比较:

我从未使用过 AVR,所以我只是根据 google 找到的指令集引用手册(以及我对其他 ISA 的 asm 的了解,例如 x86 和 ARM)来编写此内容。根据这些文档,所有这些指令都是 1 个字(2 个字节),具有 1 个周期延迟。这比 gcc4.5 的做法要好:

<小时/>

找到好的指令序列的通常方法是询问编译器AVR gcc4.5 -O3 on godbolt这样做:

short sign_extend(signed char a) { return a; }

sign_extend:
mov r18,r24 ;; IDK why gcc uses r18 and r19.

clr r19
sbrc r18,7
com r19

mov r25,r19
ret

所以它zeros R19 ,然后使用 SBRC根据 R18 的符号位(位 7)有条件地执行逻辑非 ( COM )。

我不确定额外的 MOV 是做什么用的。我也不确定为什么它会反转零而不是设置所有不依赖输入的位。 (例如 ldi r19, $FFSBR alias for it 。如果曾经存在无序执行 AVR,那么效率会更高。:P

我不确定 MOV 指令的用途。 SBRC 是非破坏性的。所以 AFAICT,一个有效的实现是

sign_extend:
clr r25
sbrc r24,7
ldi r25, $FF
ret

这仍然比 CP/SBC 更糟糕,因为如果进行跳过,SBRC 需要 2 个周期

<小时/>

我认为 SBC 对 R25 旧值的“错误依赖”在 AVR 上不是问题。在乱序 x86 CPU 上,只有 AMD 能够识别 sbb eax, eax独立于 eax 的旧值,并且仅取决于标志。 Intel CPU 就可以正常运行。 (它们确实将 xor eax,eax 等指令识别为独立指令,以及 it's the standard zeroing-idiom for x86 。)

因此,在非 AMD CPU 上,如果最后编写 EAX 的代码在缓存中丢失负载或其他高延迟的情况下执行,sbb eax, eax 甚至无法执行标志是否已准备好(即来自独立的依赖链)。但在 AMD CPU 上,它将为 EAX 启动一个新的依赖链。

无论如何,我认为 AVR 是一个相当简单的有序流水线设计,因此旧寄存器不可能成为性能地雷,除非执行(例如)缓存未命中的代码永远不会加载到其中使用了结果。 (即使是有序管道也不需要等待高延迟操作,直到有人使用结果。)

关于assembly - 如何在汇编中将有符号 8 位字节转换为有符号 16 位整数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40859123/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com