Как реализовать факториальную функцию в RISC-V - PullRequest
1 голос
/ 23 сентября 2019
    C-code  :

int factorial(int n) 
{
if (n<1) return 1;
 else return n * factorial (n-1);
}

Я пытался реализовать это, но не смог сделать много.Итак, вот моя попытка:

     goto:

 factorial:
 int factorial(int n) {
 if (n<1) goto Lthen;

 Lelse:
 tmp=factorial(n-1);
 return n*tmp;
 goto Lend;

 Lthen: return 1;
 Lend;
 }



 RISC V:
.factorial
 addi sp, sp,  -16
 sw ra, (sp)
 sw s0, 4(sp) //n
 sw s1, 8(sp) //tmp
 mv s0, a0               //a--->s0
 addi t1, zero,1 
 blt s0, t1, Lthen

   .Lelse
   mv t0, s0          // copy of n to t0
   addi s0, s0, -1   // n-1
   mv a0, s0;        // n-1--->a0
   jal factorial // factorial(a0)
   mv s1, a0         // s1=factorial(a0) //tmp
   mul a0,t0,s1        //  n*tmp ----> a0 
   ret
   j LEND



Lthen: li a0,1
ret
LEND jr ra, 0 

Может кто-нибудь сказать мне, что все в порядке, потому что я не знаю, как это проверить.И я не уверен насчет, например, возврата 1 / или любого другого значения / выражения, можем ли мы просто поместить его в a0 и сказать ret ..

Спасибо за ваше время!

Ответы [ 2 ]

0 голосов
/ 27 сентября 2019

Вот рекурсивная факториальная функция в RISC-V из краткого справочника моего RV32I-ассемблера : (комментарии приветствуются!)

.text  # recursive implementation of factorial
.globl __start
fact:       # arg: n in a0, returns n! in a1
    addi  sp, sp, -8    # reserve our stack area
    sw ra, 0(sp)    # save the return address
    li t0, 2
    blt a0, t0, ret_one # 0! and 1! == 1
    sw a0, 4(sp)    # save our n
    addi a0, a0, -1
    jal fact        # call fact (n-1)
                    # a1 <- fact(n-1)
    lw t0, 4(sp)    # t0 <- n
    mul a1, t0, a1  # a1 <- n * fact(n-1)
    j done
ret_one:
    li a1, 1
done:
    lw ra, 0(sp)    # restore return address from stack
    addi sp, sp, 8  # free our stack frame
    jr ra           # and return

__start:
    li a0, 5        # compute 5!
    jal fact
    li a0, 1        # print it
    ecall
    li a0, 17
    ecall       # and exit

Чтобы проверить это, мой любимый легкий RISC-Vсимуляторами являются Венера и Юпитер .

0 голосов
/ 25 сентября 2019

Вы должны использовать $s0 для сохраненного значения вместо $t0.

Вы должны вычесть одно из $ a0 после копирования из $s0 перед рекурсивным вызовом.

Тогда умножение будет идти между возвращаемым значением $a0 и сохраненным значением $s0.

Причина $s0 будет работать, но $t0 не будет (чтобы сохранить исходный $a0 ввод), вы предпринимаете (правильное) усилие по сохранению регистров s.

Однако вы не восстанавливаете сохраненные значения в эпилоге функции, не сокращаете стек и не перезагружаете $ra...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...