我是組裝新手,但誰能教我如何在 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)
那么,我應該將整數讀取為字串并將其轉換為整數嗎?我已經搜索過這個解決方案,但我找不到它。
uj5u.com熱心網友回復:
是的,如果您不能使用玩具系統呼叫,請讀取一個字串并total = total*10 digit對其執行操作,其中digit = c-'0'. 您需要進行擴展精度乘法,因此進行擴展精度移位可能更容易,例如(total << 3) (total << 1).
檢查Godbolt 上的編譯器輸出。例如,GCC 使用移位,clang 使用mul/ mulhu(高位無符號)表示lo * lo32x32=>64 位部分積,amul表示高半叉積(hi * lo)。它的指令更少,但取決于具有快速乘法器的 RISC-V CPU 比移位/或更快。
(RISC-V 擴展精度加法不方便,因為它沒有進位標志,您需要將進位模擬為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 的輸出比較短,所以我來展示一下:
# 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 # 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 dump and didn't load these regs before branching
ret
如果您想采用 GCC 的轉變/或策略,應該很容易看到該插槽如何插入到相同的邏輯 clang 中。您可以查看函式的編譯器輸出,例如return u64 << 3查看哪些指令是其中的一部分。
順便說一句,我在撰寫 C 時考慮到了編譯為體面的 asm,這使得編譯器可以輕松地將其轉換為do{}while帶有底部條件的回圈。我在 NASM Assembly 的答案中基于 x86 asm將輸入轉換為整數?
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/474979.html
