在汇编语言级别使用RISC-V中的大端值的最简单方法是什么?也就是说,如何将内存中的big-endian值加载到寄存器中,如何在native-endian(little-endian)中使用寄存器值,然后将其存储回big-endian中的内存中。 16、32和64位值用于许多网络协议和文件格式。
我找不到字节交换指令(相当于x86上的BSWAP或ARM上的REV)in the manual,也找不到关于大端存储和存储的任何内容。
答案 0 :(得分:4)
截至2018年8月:
在最新的RISC-V User-Level ISA Manual(2.1版)中没有提及字节交换指令。但是,该手册中有占位符,用于“ B”位操作标准扩展。该扩展程序的工作组提供的一些草稿材料是collected on GitHub。特别是,draft specification讨论了一条grev
指令(广义反向),该指令可以进行16、32和64位字节交换:
该指令提供了一条硬件指令,可以实现所有字节顺序交换,按位反转,短顺序交换,字序交换(RV64),半字节交换,字节中的按位反转等。 ,全部来自一条硬件指令。它通过控制递归树中发生反转的级别来获取单个寄存器值和一个立即数,该立即数控制发生哪个功能。
但是,扩展B工作组“由于官僚原因于2017年11月解散了”,然后他们才能最终确定规范。
因此,目前似乎没有比平常的shift-mask-或dance简单的事情了。我在GCC或clang riscv端口中找不到任何固有的汇编语言bswap。例如,下面是bswapsi2
编译器版本8.1.0-12发出的riscv64-linux-gnu-gcc
函数的反汇编(该字节交换32位值):
000000000000068a <__bswapsi2>:
68a: 0185169b slliw a3,a0,0x18
68e: 0185579b srliw a5,a0,0x18
692: 8fd5 or a5,a5,a3
694: 66c1 lui a3,0x10
696: 4085571b sraiw a4,a0,0x8
69a: f0068693 addi a3,a3,-256 # ff00 <__global_pointer$+0xd6a8>
69e: 8f75 and a4,a4,a3
6a0: 8fd9 or a5,a5,a4
6a2: 0085151b slliw a0,a0,0x8
6a6: 00ff0737 lui a4,0xff0
6aa: 8d79 and a0,a0,a4
6ac: 8d5d or a0,a0,a5
6ae: 2501 sext.w a0,a0
6b0: 8082 ret
答案 1 :(得分:3)
RISC-V ISA没有明确的字节交换指令。最好的选择是使用内置的C来执行此计算,这在GCC领域将类似于__builtin_bswap32()
。这为编译器提供了尽可能多的信息,因此可以做出正确的决策。使用当前定义的ISA集合,您几乎肯定会最终调用例程,但是如果定义了B扩展名,您将透明地获得更好的生成代码。完整的已定义内建函数可在线获得:https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html。
如果您在汇编中仍然这样做,那么最好的选择是调用现有的字节交换例程。 __bswapsi2
是32位交换的标准规范,它是libgcc的一部分-无论如何,您可能都在使用它,因此它将存在。那就是编译器当前正在做的事情,因此,当有更好的实现可用时,您所失去的就是取消函数调用。
作为一个具体示例,这是我的示例C函数
unsigned swapb(unsigned in) { return __builtin_bswap32(in); }
和生成的程序集
swapb:
addi sp,sp,-16
sd ra,8(sp)
call __bswapsi2
ld ra,8(sp)
sext.w a0,a0
addi sp,sp,16
jr ra
答案 2 :(得分:2)
请注意,虽然有一个很好的指令方便且方便,但其他答案中使用的__bswapsi2函数将在1.5 GHz HiFive Unleashed上以大约400 MB / s的速度运行,这比gigE界面将一直在移动数据。
即使在以默认256 MHz运行的HiFive1上,它也将以60 MB / s的速度运行,并且您只有16 KB的RAM和一堆GPIO,您不会以超过几兆赫或可能是10兆赫兹。
我在BitManipulation工作组中。完整的GREV指令需要相当多的硬件(接近乘法器),因此小型微控制器可能永远不会包含它。但是,我们计划使用相同的GREVI操作码来实现全字位反转和字节顺序反转,并将其实现为不需要太多电路的更简单的特殊情况指令,希望每个人都可以包括它们。
答案 3 :(得分:2)
与x86不同,RISC-V没有类似movbe
的东西(可以在一条指令中加载和字节交换)。
因此,在RISC-V上,您照常加载/存储,并且在加载/存储之后/之前,必须用额外的指令交换字节。
RISC-V "B" (Bitmanip) extension(版本0.92)包含通用的位反转指令(grev
,grevi
)和一些可用于字节交换的伪指令:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
RISC-V ARM X86 Comment
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
rev RBIT ☐ bit reverse
rev8.h REV16 ☐ byte-reverse half-word (lower 16 bit)
rev8.w REV32 ☐ byte-reverse word (lower 32 bit)
rev8 REV BSWAP byte-reverse whole register
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
(基于表格2.5,RISC-V Bitmanip Extension V0.92,第18页)
截至2020-03,“ B”扩展名处于草稿状态,因此对硬件和仿真器的支持受到限制。
没有“ B”扩展名,您必须使用几个基本指令来实现字节交换。参见"B" specification中的第16页,或查看__builtin_bswap16
,__builtin_bswap32
和__builtin_bswap64
gcc / clang内部函数的反汇编代码。