riscv 指令的 asm 易失性操作数用法

问题描述 投票:0回答:1

我正在尝试编写一个 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地址而不是该寄存器的内容。

我不断收到一条错误消息,指出不可能的约束。我不太确定这是什么意思。

提前致谢!

c assembly inline-assembly riscv
1个回答
0
投票

你的示例代码很混乱,它加载了字节 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
© www.soinside.com 2019 - 2024. All rights reserved.