谁能帮助我从32位RISC-V中的控制台阅读64位

发布于 2025-01-28 18:14:11 字数 716 浏览 5 评论 0 原文

我是集会的新手,但是有人可以教我如何从32位RISC-V中的控制台阅读64位吗?

    .eqv SYS_EXITO, 10
    .eqv CON_PRTSTR, 4
    .eqv CON_PRTINT, 1
    .eqv CON_RDINT, 5
    .eqv BUFSIZE, 100
    .data
prompt:
    .asciz "Read 64 bit integer:"
result:
    .asciz "Output:"
    
buf:
    .space BUFSIZE
    .text

main:
    la a0, prompt
    li a7, CON_PRTSTR
    ecall 

    la a0, buf
    li a1, BUFSIZE
    li a7, CON_RDINT
    ecall

然后我们我输入4294967295,发生了以下错误。

Error in /private/var/folders/bf/t4py6npj0v38grsvrgvq1dx00000gn/T/hsperfdata_sotarosuzuki/riscv1.asm line 24: Runtime exception at 0x00400020: invalid integer input (syscall 5)

因此,我应该将整数读为字符串并将其转换为整数吗? 我已经搜索了此解决方案,但是找不到。

I am new to assembly, but could anyone teach me how to read 64 bit from console in 32 bit RISC-V?

    .eqv SYS_EXITO, 10
    .eqv CON_PRTSTR, 4
    .eqv CON_PRTINT, 1
    .eqv CON_RDINT, 5
    .eqv BUFSIZE, 100
    .data
prompt:
    .asciz "Read 64 bit integer:"
result:
    .asciz "Output:"
    
buf:
    .space BUFSIZE
    .text

main:
    la a0, prompt
    li a7, CON_PRTSTR
    ecall 

    la a0, buf
    li a1, BUFSIZE
    li a7, CON_RDINT
    ecall

Then we I input 4294967295, the following error occured.

Error in /private/var/folders/bf/t4py6npj0v38grsvrgvq1dx00000gn/T/hsperfdata_sotarosuzuki/riscv1.asm line 24: Runtime exception at 0x00400020: invalid integer input (syscall 5)

So, should I read the integers as string and convert it to integer?
I have searched for this solution, but I cannot find it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

最单纯的乌龟 2025-02-04 18:14:11

是的,如果您无法使用玩具系统调用,请阅读字符串并在其上使用 total*10 + digit ,其中 digit = c-'0' 。您需要进行扩展推迟乘法,因此进行扩展的precision shifts 喜欢(total&lt;&lt; 3) +(总计&lt;&lt;&lt; 1)< /代码>。

Check compiler output

(RISC-V扩展推迟添加是不方便的,因为它没有随身携带标志,您需要将随身携带效仿为 unsigned sum = a+b; anctry> crand = sum&lt; a ;

#include <stdint.h>

uint64_t strtou64(unsigned char*p){
    uint64_t total = 0;
    unsigned digit = *p - '0';    // peeling the first iteration is usually good in asm
    while (digit < 10) {     // loop until any non-digit character
        total = total*10 + digit;
        p++;                // *p was checked before the loop or last iteration
        digit = *p - '0';   // get a digit ready for the loop branch
    }
    return total;
}

clang的输出较短,所以我会显示。当然,它遵循标准调用约定,将指针纳入 a0 中,然后在一对寄存器中返回一个64位整数, a1:a0

# rv32gc clang 14.0  -O3
strtou64:
        mv      a2, a0
        lbu     a0, 0(a0)         # load the first char
        addi    a3, a0, -48       # *p - '0'
        li      a0, 9
        bltu    a0, a3, .LBB0_4   # return 0 if the first char is a non-digit
        li      a0, 0               # total in a1:a0 = 0   ;  should have done these before the branch
        li      a1, 0                           # so a separate ret wouldn't be needed
        addi    a2, a2, 1           # p++
        li      a6, 10              # multiplier constant
.LBB0_2:                            # do{
        mulhu   a5, a0, a6            # high half of (lo(total) * 10)
        mul     a1, a1, a6            # hi(total) * 10
        add     a1, a1, a5            # add the high-half partial products
        mul     a5, a0, a6            # low half of  (lo(total) * 10)
        lbu     a4, 0(a2)                # load *p
        add     a0, a5, a3            # lo(total) =  lo(total*10) + digit
        sltu    a3, a0, a5            # carry-out from that
        add     a1, a1, a3            # propagate carry into hi(total)
        addi    a3, a4, -48             # digit = *p - '0'
        addi    a2, a2, 1                # p++ done after the load; clang peeled one pointer increment before the loop
        bltu    a3, a6, .LBB0_2     # }while(digit < 10)
        ret
.LBB0_4:
        li      a0, 0               # return 0 special case
        li      a1, 0               # because clang was dumb and didn't load these regs before branching
        ret

如果要:使用GCC的偏移/策略,应该直接查看该插槽如何使用相同的逻辑clang。您可以查看编译器输出的函数,例如返回U64&lt;&lt; 3 查看哪些说明是其中的一部分。

顺便说一句,我牢记了Compent的COMM,我牢记了COMPLING,这使编译器可以轻松地将其转换为 do {},而循环却在底部具有条件。我的答案中的x86 ASM基于

Yeah, if you can't use the toy system calls, read a string and do total = total*10 + digit on it, where digit = c-'0'. You'll need to do extended-precision multiply, so it's probably easier to do extended-precision shifts like (total << 3) + (total << 1).

Check compiler output on Godbolt. For example, GCC using shifts, clang using mul/mulhu(high unsigned) for the lo * lo 32x32=>64-bit partial product, and a mul for the high half cross product (hi * lo). It's fewer instructions, but depends on a RISC-V CPU with a fast multiplier to be faster than shift/or.

(RISC-V extended-precision addition is inconvenient since it doesn't have a carry flag, you need to emulate carry-out as unsigned sum = a+b; carry = sum<a;)

#include <stdint.h>

uint64_t strtou64(unsigned char*p){
    uint64_t total = 0;
    unsigned digit = *p - '0';    // peeling the first iteration is usually good in asm
    while (digit < 10) {     // loop until any non-digit character
        total = total*10 + digit;
        p++;                // *p was checked before the loop or last iteration
        digit = *p - '0';   // get a digit ready for the loop branch
    }
    return total;
}

Clang's output is shorter, so I'll show it. It of course follows the standard calling convention, taking the pointer in a0, and returning a 64-bit integer in a pair of registers, a1:a0:

# rv32gc clang 14.0  -O3
strtou64:
        mv      a2, a0
        lbu     a0, 0(a0)         # load the first char
        addi    a3, a0, -48       # *p - '0'
        li      a0, 9
        bltu    a0, a3, .LBB0_4   # return 0 if the first char is a non-digit
        li      a0, 0               # total in a1:a0 = 0   ;  should have done these before the branch
        li      a1, 0                           # so a separate ret wouldn't be needed
        addi    a2, a2, 1           # p++
        li      a6, 10              # multiplier constant
.LBB0_2:                            # do{
        mulhu   a5, a0, a6            # high half of (lo(total) * 10)
        mul     a1, a1, a6            # hi(total) * 10
        add     a1, a1, a5            # add the high-half partial products
        mul     a5, a0, a6            # low half of  (lo(total) * 10)
        lbu     a4, 0(a2)                # load *p
        add     a0, a5, a3            # lo(total) =  lo(total*10) + digit
        sltu    a3, a0, a5            # carry-out from that
        add     a1, a1, a3            # propagate carry into hi(total)
        addi    a3, a4, -48             # digit = *p - '0'
        addi    a2, a2, 1                # p++ done after the load; clang peeled one pointer increment before the loop
        bltu    a3, a6, .LBB0_2     # }while(digit < 10)
        ret
.LBB0_4:
        li      a0, 0               # return 0 special case
        li      a1, 0               # because clang was dumb and didn't load these regs before branching
        ret

If you want to go with GCC's shift/or strategy, it should be straightforward to see how that slots in to the same logic clang is using. You can look at compiler output for a function like return u64 << 3 to see which instructions are part of that.

And BTW, I wrote the C with compiling to decent asm in mind, making it easy for the compiler to transform it into a do{}while loop with the condition at the bottom. I based it on the x86 asm in my answer on NASM Assembly convert input to integer?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文