我正在尝试编写一个 C 函数,它采用 riscv 加载/存储 (h/w/d) 指令的 32 位指令编码,并将其展开为一系列加载/存储 (b) 指令。
我将如何在 asm 易失性中执行此操作?
这是我正在尝试做的一个例子:
输入参数:0032a303(这是一个
lw t1,3(t0)
)。
我想按如下方式展开:
lb t2, 3(t0);
slli t2, t2, 0;
or t1, t1, t2;
lb t2, 4(t0);
slli t2, t2, 8;
or t1, t1, t2;
lb t2, 3(t0);
slli t2, t2, 16;
or t1, t1, t2;
lb t2, 3(t0);
slli t2, t2, 24;
or t1, t1, t2;
t2 这是一个被破坏的寄存器,我不担心这些寄存器被污染。 我想在 asm 易失性块中执行此操作。
这是我尝试过的:
void load_bytes(reg_t rd, reg_t rs1, reg_t imm, reg_t iter){
for (int i = 0; i < iter ; i ++) {
// "lb" from *(rs1 + imm + i) into t0
// "slli" t0 by (iter - i) bytes
// "or" t0 with rd
asm volatile(
"lb t0, %[imm_val](%[rs1_val])\n"
"slli t0, t0, %[shift_val]\n"
"or %[rd_val], %[rd_val], t0\n"
: [rd_val] "+r" (rd)
: [rs1_val] "r" (rs1), [imm_val] "i" (imm + i), [shift_val] "i" (sizeof(byte_t)*iter - i)
: "t0"
);
}
}
我不认为我所做的事情是正确的,而且我也不认为扩展的 asm 文档在这里很有帮助。有人可以帮我理解我在编写内联汇编时犯了什么错误吗?
我最初尝试将其完全用asm编写,但问题似乎是该寄存器的枚举被视为mem地址而不是该寄存器的内容。
我不断收到一条错误消息,指出不可能的约束。我不太确定这是什么意思。
提前致谢!
你的示例代码很混乱,它加载了字节 3、4、3、3。它没有进行零初始化
t1
。 lb
符号延伸,这不太可能是您想要的。当你的 C 代码相反时,它也会按递增顺序移动。 sizeof(byte_t)
可能会是 1,但您需要的是位而不是字节进行移位。 i
永远不会等于iter
,所以你的iter - i
永远不会产生0,这又与你的描述相反。产生错误的直接原因是移位计数需要是汇编时间常数。 iter
有什么意义?您希望它适用于多种尺寸吗?
这是足够简单的代码,C 编译器应该完全能够处理。另外,您可能想返回结果,因此
rd
应该是一个指针。
有什么问题:
void load_bytes(reg_t* rd, reg_t rs1, reg_t imm)
{
uint8_t* p = (uint8_t*) rs1 + imm;
*rd = p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
}
不确定练习的重点是什么,为什么你不想只使用负载(可能还有字节交换)。
如果你想要纯汇编版本,可能看起来像:
add a2,a2,a1
lbu a3,0(a2)
lbu a1,1(a2)
slli a1,a1,8
or a3,a3,a1
lbu a1,2(a2)
slli a1,a1,16
or a3,a3,a1
lbu a1,3(a2)
slli a1,a1,24
or a3,a3,a1
sw a3,0(a0)
ret