如何在MIPS汇编中执行递归操作?

时间:2013-09-24 20:43:08

标签: assembly recursion mips

我的任务是编写一个递归MIPS汇编程序,在program1中执行以下数学运算:

(-3)*function1(n-2) + 7*function1(n-3) + 15

该程序以c:

为模型
 // The function1 is a recursive procedure defined by:
// function1(n) = 1 if n <= 2
// = (-3)*function1(n-2) + 7*function1(n-3) + 15 otherwise.
int function1(int n)
{
 if (n <= 2)
 {
 return 1;
 }
 else
 {
 int comp = (-3)*function1(n-2) + 7*function1(n-3) + 15;
 return comp;
 }
}
// The main calls function1 by entering an integer given by a user.
void main()
1 of 2{
 int ans, n;
 printf("Enter an integer:\n");
 // read an integer from user and store it in "n"
 scanf("%d", &n);
 ans = function1(n);
 // print out the solution computed by function 1
 printf("The solution is: %d\n", ans);
 return;
}

我编写了代码,编译并执行正常,但给了我不正确的值:

 .data
mes1:   .asciiz "\nEnter an integer: "
mes2:   .asciiz "The solutinon is: "

.text
    .globl main

main:
    #Display message
    la $a0, mes1
    li $v0, 4
    syscall
    #Retrieve Value
    li $v0, 5
    syscall
    #Store value into $a0 and jump to function1
    move $a0, $v0
    jal function1

    #Store return value to $t0
    move $t0, $v0

    #Display solution
    la $a0, mes2
    li $v0, 4
    syscall
    move $a0, $t0
    li $v0, 1
    syscall

    #End
    li $v0, 10
    syscall



function1:
    #Store return address
    addi $sp, $sp, -4
    sw $ra, 0($sp)

    #Store $a0 to stack
    addi $sp, $sp, -4
    sw $a0, 0($sp)

    #If($a0<3):$t0=1:$t0=0
    slti $t0, $a0, 3

    #if($t0=0):math
    beq $t0, $zero, math
    addi $v0, $zero, 1

    #Retrieve from stack
    lw  $a0, 0($sp)
    addi    $sp, $sp, 4
    lw  $ra, 0($sp)
    addi    $sp, $sp, 4

    jr $ra

math:
    addi $a0, $a0, -2
    jal function1
    mul $s0 $v0, -3
    addi $a0, $a0, -3
    jal function1
    mul $s1, $v0, 7
    add $s1, $s0, $s1
    addi $v0, $s1, 15

    #Retrieve from stack
    lw  $a0, 0($sp)
    addi    $sp, $sp, 4
    lw  $ra, 0($sp)
    addi    $sp, $sp, 4

    jr $ra

当我输入6时,它应该输出91.目前,它输出44.也许更令人不安,每当我输入任何值时,输出数字总是可被4整除。对于我的生活,我无法想象出了什么问题。有人可以建议吗?

- 编辑 -

我考虑了@TomásBadan关于保护$ a0的评论。我试过了:

math:
    #Store $a0 to stack
    addi $sp, $sp, -4
    sw $a0, 0($sp)

    addi $a0, $a0, -2
    jal function1
    mul $s0, $v0, -3

    #Retrieve from stack
    lw  $a0, 0($sp)
    addi    $sp, $sp, 4

    addi $a0, $a0, -3
    jal function1
    mul $s1, $v0, 7
    add $s1, $s0, $s1
    addi $v0, $s1, 15

    #Retrieve from stack
    lw  $a0, 0($sp)
    addi    $sp, $sp, 4
    lw  $ra, 0($sp)
    addi    $sp, $sp, 4

    jr $ra

但它仍然返回不正确的值,尽管更接近正确的数字。

1 个答案:

答案 0 :(得分:3)

好吧,我会指定一些错误,这不是一个完整的调试会话:

function1:
...
#If($a0<3):$t0=1:$t0=0
slti $t0, $a0, 3

#if($t0=0):sub1
beq $t0, $zero, math

#Load 4 to $v0
addi $v0, $zero, 4 // I thought you should return 1
...

math:
addi $a0, $a0, -2  // you are changing $a0 here
jal function1
lw $t2, constn3
mult $v0, $t2
mflo $t0           // you use $t0 to keep temporary values, but you function change $t0 too (look above, at instruction slti). You need to protect its contents
addi $a0, $a0, -3  // but you need your original value here
jal function1
lw $t2, const7
mult $v0, $t2

<强> EDITED

正如我在评论中所说,你需要保留所有需要在过程调用之间保持状态的寄存器。

如果您遵循MIPS约定调用,则表示您必须保存在函数内部使用的s *系列中的任何寄存器。您使用其中两个s0和s1,因此,您必须将它们保存在入口点。嗯,这是另一个问题,你必须只有一个入口点和一个出口点。

function1:
#Store return address
addi $sp, $sp, -12
sw $ra, 0($sp)
sw $s0, 4($sp)
sw $s1, 8($sp)

#If($a0<3):$t0=1:$t0=0
slti $t0, $a0, 3

#if($t0=0):math
beq $t0, $zero, math
addi $v0, $zero, 1
j exit

math:
addi $sp, $sp, -4
sw $a0, 0($sp)
addi $a0, $a0, -2
jal function1
lw  $a0, 0($sp)
addi    $sp, $sp, 4

addi $t6, $zero, -3
mul $s0 $v0, $t6

addi $sp, $sp, -4
sw $a0, 0($sp)
addi $a0, $a0, -3
jal function1
lw  $a0, 0($sp)
addi    $sp, $sp, 4

addi $t6, $zero, 7
mul $s1, $v0, $t6
add $s1, $s0, $s1
addi $v0, $s1, 15

#Retrieve from stack
exit:
lw $ra, 0($sp)
lw $s0, 4($sp)
lw $s1, 8($sp)
addi    $sp, $sp, 12

jr $ra