Java到MIPS程序集转换(递归方法)

时间:2015-02-18 20:59:48

标签: java assembly recursion mips modular

我正在尝试在MIPS程序集中实现递归模幂运算程序。该程序允许用户输入三个正数x,n和p,并输出(x ^ n)mod p。我能够用Java编写代码,但是我很难将代码转换为MIPS Assembly。这是我的Java代码:

int modPow(int x, int n, int p) {
    x = x%p;

    if (n == 0)
        return 1;
    else if (n == 1)
        return x;
    else if (n%2 == 0)
        return modPow(x*x%p, n/2, p);
    else
        return x*modPow(x, n-1, p)%p;
}

我意识到我最大的问题是在MIPS中调用方法,特别是递归。以下是我到目前为止的情况:

.text

main:li $v0, 5          #store x in $v0
     syscall                
     move $s0, $v0      #move x to $s0
     li $v0, 5          #store n in $v0
     syscall                
     move $s1, $v0      #move n to $s1
     li $v0, 5          #store p in $v0
     syscall                
     move $s2, $v0      #move p to $s2
     div $s0, $s2
     mfhi $s0           #x = x % p
     bne $s1, $zero, L1 #Branch to first ElseIf if !(n==0)
     li $a0, 1          #return value stored as 1
     li $v0, 1          #output 1 (what is stored in $a0)
     syscall

L1: li $t0, 1           #$t0 = 1
    bne $s1, $t0, L2    #Branch to second ElseIf if !(n==1)
    move $a0, $s1       #$a0 = n
    li $v0, 1           #output n (stored in $a0)
    syscall

L2: li $t0, 2           #t0 = 2
    div $s1, $t0            
    mfhi $t0            #$t0 = n % 2
    bne $t0, $zero, L3  #Branch to else if !(n%2==0)
    mflo $s1            #$s1 = floor(n/2)
    mult $s0, $s0       #x * x
    mfhi $s0            #x = x * x
    div $s0, $s2
    mfhi $s0            #$s0 = (x * x) % p
    jal main

L3: li $t0, 1           #$t0 = 1
    sub $s1, $t0        #n = n-1
    jal main
    mult $s0, $a0       #x * mod(x, n-1, p)
    mfhi $s0            #x = x * mod(x, n-1, p)
    div $s0, $s2
    mfhi $a0            #x = x * mod(x, n-1, p) % p stored in $a0
    li $v0, 1
    syscall

我使用系统调用指令来获取用户的输入并将内容输出给用户。做大部分算术都很简单,我的大多数麻烦都是用这些方法调用,特别是在递归中。任何人都可以帮助我吗?

2 个答案:

答案 0 :(得分:0)

在您的Java代码中,您递归调用modPow(),它运行其函数参数,但在汇编代码中,您将递归main(),它执行I / O操作。这可能不是你想要的。定义标签modPow:并在那里实现您的功能。此外,Java代码比它需要的更复杂,这反过来又难以实现它。

1.如果if条件以return声明结尾,则不需要else
2.如果你不打算使用它,你不需要计算模数 3.您不需要在两个位置计算模数(在函数体和递归调用中)。但是想要计算返回值的模数 4.对于所有n,pow(1,n)为1 5.对于所有n!= 0,pow(0,n)为0(可论证,但if (!n)已涵盖)
尝试:

int modPow(int x, int n, int p)
{
  if (!n)
    return 1;
  x %= p;
  if ( !x || x == 1 || n ==1 )
    return x;
  if (n % 2)
    return x*modPow(x, n-1, p)%p;
  return modPow(x*x, n/2, p);
}

也就是说,要在MIPS上调用函数,需要在堆栈中保存链接寄存器的当前值(返回地址):

addi $sp, $sp, -4  #on 32-bit MIPS, 4 byte word 
sw $ra, ($sp)      #save return address of current function
...                #load function arguments to $a0...
jal functionToCall #call
...                #use return value in $v0
lw $ra, ($sp)      #restore return address
addi $sp, $sp, 4   #restore stack-pointer
jr $ra             #return

答案 1 :(得分:0)

递归有两个规则:

  1. 保存您的寄信人地址

    • 这是调用你的函数的地址,通常是寄存器$ ra。将其保存在堆栈中(不在其中一个保存寄存器中 - $ s0 ... 7)
  2. 跳转并链接(jal)到您要调用的方法

  3. 我认为您的代码存在的问题是您似乎没有做这些