Algorithm 用mips编写俄罗斯农民乘法

Algorithm 用mips编写俄罗斯农民乘法,algorithm,math,assembly,mips,Algorithm,Math,Assembly,Mips,我想写一个程序,使用俄罗斯农民乘法与mips,但我面临一些问题 / A method to multiply two numbers using Russian Peasant method unsigned int russianPeasant(unsigned int a, unsigned int b) { int res = 0; // initialize result // While second number doesn't become 1 whil

我想写一个程序,使用俄罗斯农民乘法与mips,但我面临一些问题

/ A method to multiply two numbers using Russian Peasant method
unsigned int russianPeasant(unsigned int a, unsigned int b)
{
    int res = 0;  // initialize result

    // While second number doesn't become 1
    while (b > 0)
    {
         // If second number becomes odd, add the first number to result
         if (b & 1)
             res = res + a;

         // Double the first number and halve the second number
         a = a << 1;
         b = b >> 1;
     }
     return res;
}
拜托,有人能帮我吗? 修复“错误:无效的程序计数器值:0x00000000” 我搜索了如何修复它,但我对$ra有一个问题
如何将返回地址正确地保存在$ra中?

jr$ra将跳转到寄存器
$ra
中存储的地址,该地址不是由您的代码设置的,因此它仍然是零(运行代码之前来自MARS的初始寄存器值)。CPU将跳转到地址0,这是失败的,并报告

/ A method to multiply two numbers using Russian Peasant method
unsigned int russianPeasant(unsigned int a, unsigned int b)
{
    int res = 0;  // initialize result

    // While second number doesn't become 1
    while (b > 0)
    {
         // If second number becomes odd, add the first number to result
         if (b & 1)
             res = res + a;

         // Double the first number and halve the second number
         a = a << 1;
         b = b >> 1;
     }
     return res;
}
要使用
jr$ra
从某些代码中“返回”,必须首先使用
jal
指令(或修改
$ra
内容的其他指令)来设置
$ra
。另外,当您要嵌套多个
jal
子例程调用时,您必须存储/恢复周围外部调用的
$ra
,以免在下一个嵌套
jal
时丢失值

/ A method to multiply two numbers using Russian Peasant method
unsigned int russianPeasant(unsigned int a, unsigned int b)
{
    int res = 0;  // initialize result

    // While second number doesn't become 1
    while (b > 0)
    {
         // If second number becomes odd, add the first number to result
         if (b & 1)
             res = res + a;

         // Double the first number and halve the second number
         a = a << 1;
         b = b >> 1;
     }
     return res;
}
下面的代码是使用paired
jal
+
jr$ra
进行类似“子例程”的调用的示例,也是此类算法在汇编中实现的简单性示例(因为事实上,C源代码更像C中的汇编,所以您的经验不足使您采取了一种非常复杂的方法来实现一些可以在汇编中以1:1的比例使用原始C源代码实现的东西):

/ A method to multiply two numbers using Russian Peasant method
unsigned int russianPeasant(unsigned int a, unsigned int b)
{
    int res = 0;  // initialize result

    // While second number doesn't become 1
    while (b > 0)
    {
         // If second number becomes odd, add the first number to result
         if (b & 1)
             res = res + a;

         // Double the first number and halve the second number
         a = a << 1;
         b = b >> 1;
     }
     return res;
}
以及子例程本身,它可以使用
a0
a1
中的参数调用,并在
v0
中返回结果

/ A method to multiply two numbers using Russian Peasant method
unsigned int russianPeasant(unsigned int a, unsigned int b)
{
    int res = 0;  // initialize result

    // While second number doesn't become 1
    while (b > 0)
    {
         // If second number becomes odd, add the first number to result
         if (b & 1)
             res = res + a;

         // Double the first number and halve the second number
         a = a << 1;
         b = b >> 1;
     }
     return res;
}
# input: $a0 = a, $a1 = b
# output: $v0 = a * b
russianPeasant:
    li      $v0, 0          # res = 0
    beq     $a1, $zero, russianPeasant_b_zero
    nop     # neutralize "Delayed branching" setting ("nop" works with both ON/OFF setting)
russianPeasant_while_b:
    andi    $at, $a1, 1     # test if b is odd, for even b skip the res = res + a
    beq     $at, $zero, russianPeasant_b_even
    nop     # but such neutralization comes with performance cost of course
    add     $v0, $v0, $a0   # res = res + a
russianPeasant_b_even:
    sll     $a0, $a0, 1     # a = a << 1
    srl     $a1, $a1, 1     # b = b >> 1
    bne     $a1, $zero, russianPeasant_while_b  # repeat when (b != 0)
    nop     # on real MIPS production code the instructions are reordered to avoid useless nop
russianPeasant_b_zero:
    jr      $ra             # return res
    nop

最后一行的
jr$ra
应该实现什么?看起来像MARS/SPIM环境(根据
syscall
用法猜测),其中,
$ra
在程序启动时为零,我看不到任何
jal
move/add/…
会改变
$ra
,所以看起来你面临的问题是在代码中添加随机指令,而不是弄清楚你到底想做什么,并且只这么做。是的,我知道,但不知道怎么做在我的代码中使用jal,它可能会破坏我的代码。是的,我使用MARS environment
jal
is jump,它还设置了带有以下指令地址的
$ra
(或者下一个,甚至不确定是哪一个,因为MIPS CPU的延迟分支插槽,这使得所有的跳跃更加复杂。.您的代码似乎期望该功能关闭,因此您的MARS正在模拟没有分支延迟插槽的虚拟简化MIPS CPU).那么最后一条指令应该实现什么?为什么要放在那里
jr$ra
?要结束代码执行,请使用带有终止函数的
syscall
。要跳回代码,请使用纯跳转到标签。要使用“子例程”学习如何使用
jal+jr$ra
。我刚刚编辑了我的帖子,我希望你现在明白我在寻找什么我明白了你想编码什么,我不明白你是怎么得到你的代码的-好吧,我知道怎么做的,因为你只是在学习汇编,没有花足够的时间+练习CPU指令集目前还不了解汇编中某些事情是如何完成的常用习惯用法,但其结果有助于对您编写的所有内容进行详细检查,与您的讲座和可用的说明进行交叉检查,并试图找出哪些内容看起来合理,哪些内容是从C源代码过度转移而来的错综复杂的混乱。然后将其删除,然后开始over@kevin73??当然可以,但这不是重点,重点是,你是否能理解它是如何工作的……继续学习和使用调试器进行实验,并在评论中询问我是否有不可理解的东西。如果你只是复制并作为你的作品提交,你是在浪费每个人的时间。哦,好吧,我只是看到我是一个真正的新手所以我必须学习much@kevin73是的,但这很好,组装有相当陡峭的学习曲线。事实上,这并不难,它只是一个简单的过度增长的计算器,仅此而已,但它需要一段时间,直到它进入你的脑海,你将学习这种机器般的思维方式,纯粹的数学+确定性的方法,永远不会让你的胸罩在中,你可以通过你所希望的或一些错误的假设来转移你对真实状态的注意力。在获得了机器的那种感觉之后,你可能会发现程序集令人惊讶地“简单”易懂(这是实现某些东西所需的代码量,这使它变得“复杂”)。