简体   繁体   English

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

[英]Java to MIPS assembly convert (recursive method)

I am trying to implement a recursive modular exponentiation program in MIPS assembly. 我正在尝试在MIPS程序集中实现递归模幂运算程序。 The program lets the user input three positive numbers x, n and p, and outputs (x^n) mod p. 该程序允许用户输入三个正数x,n和p,并输出(x ^ n)mod p。 I was able to write the code for it in Java, but I am having a difficult time converting that code to MIPS Assembly. 我能够用Java编写代码,但是我很难将代码转换为MIPS Assembly。 Here is my Java code: 这是我的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;
}

I realize that my biggest issue is calling methods in MIPS, especially recursively. 我意识到我最大的问题是在MIPS中调用方法,特别是递归。 Here is what I have so far: 这是我到目前为止:

.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

I use syscall instructions to take the input from the user and to output things to the user. 我使用系统调用指令来获取用户的输入并将内容输出给用户。 Doing most of the arithmetic is simple enough, most of my trouble is with these method calls, especially in recursion. 做大部分算术都很简单,我的大多数麻烦都是用这些方法调用,特别是在递归中。 Can anyone help me? 谁能帮我?

In your Java-code, you're recursively calling modPow() , which operates on its function arguments, but in your assembly-code, you're recursing into main() , which does I/O. 在你的Java代码中,你递归地调用modPow() ,它运行在它的函数参数上,但在你的汇编代码中,你正在递归到main() ,它执行I / O. This is probably not what you want. 可能不是你想要的。 Define a label modPow: and implement your function there. 定义标签modPow:并在那里实现您的功能。 Also, the Java-code is more complicated than it needs to, which in turn makes implementing it unnecessarily difficult. 此外,Java代码比它需要的更复杂,这反过来又使得实现它变得不必要地困难。

1. If your if -condition ends in a return statement, you don't need an else 1.如果ifreturn语句结束,则不需要else
2. You don't need to calculate the modulo if you're not going to use it. 2.如果你不打算使用它,你不需要计算模数。
3. You don't need to calculate the modulo in two places (in function body and recursive call). 3.您不需要在两个位置计算模数(在函数体和递归调用中)。 You do want to calculate the modulo for your return value, though. 但是,您确实希望计算返回值的模数。
4. pow(1,n) is 1 for all n. 所有n的pow(1,n)为1。
5. pow(0,n) is 0 for all n!=0 (arguable, but already covered by if (!n) ) 5.对于所有n!= 0,pow(0,n)为0(可论证,但已被if (!n)覆盖)

Try: 尝试:

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);
}

That said, to call a function on MIPS, you need to save the current value of the link register (return address) on the stack: 也就是说,要在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

There are 2 rules to recursion: 递归有两个规则:

  1. Save your return address 保存您的寄信人地址

    • This is the address of the function that called you and this is usually register $ra. 这是调用你的函数的地址,这通常是寄存器$ ra。 Save this on the stack, (not in one of the save registers - $s0...7) 将其保存在堆栈中(不在其中一个保存寄存器中 - $ s0 ... 7)
  2. Jump and link (jal) to the method you want to call 跳转并链接(jal)到您要调用的方法

I think the problem your code has is that you don't seem to be doing either of these 我认为你的代码存在的问题是你似乎没有做过这些

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM