C代码转换成MIPS汇编

3
我正在尝试将C代码转换为MIPS汇编。以下是两个C代码片段。问题在于我的解决方案与标准解决方案不同,而且我也不理解标准解决方案。希望有人能够解释一下以下两个mips汇编代码片段。
首先,任务需要的仅有以下MIPS指令:lw、add、beq、bne和j。 寄存器: $s3包含i $s4包含j $s5包含k A是一个32位整数数组,其初始地址在$s6中 $t0和$t1可用于存储临时变量
第一个是一个简单的do-while循环:
do {
    i = i + j;
} while(A[i] == k);

MIPS汇编

loop: add $s3, $s3, $s4   // this is i = i+j
      add $t1, $s3, $s3  // from now on
      add $t1, $t1, $t1  // I cant follow anymore
      add $t1, $t1, $s6  // What happens in these three lines?
      lw  $t0, 0($t1)    // 0($t1) is new for me. What does this zero do?
      beq $t0, $s5, loop

现在是第二段C代码:

if ( i == j )
    i = i + A[k];
else if( i == k )
    i = i + A[j];
else
   i = i + k;

这里是MIPS汇编代码:

       bne $s3, $s4, Else1  // this line is if(i==j)
       add $t1, $s5, $s5   // from here on
       add $t1, $t1, $t1   // till
       add $t1, $t1, $s6  // 
       lw  $t0, 0($t1)    //
       add $s3, $s3, $t0  // here I don't understand
       j done
ELSE1: bne $s3, $s5, Else2  // this line is if(i==k)
       add $t1, $s4, $s4   // The same game as above
       add $t1, $t1, $t1
       add $t1, $t1, $s6
       lw  $t0, 0($t1)
       add $s3, $s3, $t0  // till here
       j done
ELSE2: add $s3, $s4, $s5

有人能解释一下到底发生了什么吗?这会非常有帮助。

3个回答

2

好的,最有趣且难以理解的代码如下:添加 $t1,

add $t1, $s5, $s5
add $t1, $t1, $t1
add $t1, $t1, $s6

这段代码将$s5乘以4,然后将结果存储在$t1中,接着加上$s6。这等同于:

$t1 = A[k]

理解了这一点,代码看起来就清晰多了。

关于lw $t0, 0($t1)

你可以在地址中使用偏移量。这里的偏移量为0。


1

lw 是装载指令。这里的模式是间接寻址,最常见的是:

lw $t2, ($t0)

但是你也可以包括一个字节偏移量,
lw $t2, 4($t0)   # load word at RAM address ($t0 + 4) into register $t2

编译器只是在非偏移版本中放置了0占位符。
因此,要加载 A[i],您需要完成两件事。取 A[] 的基地址,然后加上 i 倍的 sizeof(A[0])。我猜测 A 中的值为32位。
add $t1, $s3, $s3
$t1 = j + j 或 2 * j
add $t1, $t1, $t1
$t1 = $t1 + $t1 或 j+j+j+j 或 4 * j。那么为什么要这样做呢?嗯,直接乘法在时钟周期方面很慢。下一个选择是移位操作,但在这种情况下,编译器设计者决定两个加法比一个移位更好。
add $t1, $t1, $s6

我猜测$s6A[]的基地址。所以最终结果是'$t1 = A[] + 4 * j`。

好的。现在一切似乎清晰了一点。但我对偏移量有个问题。lw $t2, 0($t0) 等价于加载 ($t0 + 0) 处的地址。在上述情况下,我能否省略 "0",只使用 lw $t2, ($t0) 呢? - user2965601
是的,在我找到的MIPS汇编器页面中,“lw $t2,($t0)”是一种有效的形式。 - woolstar
嗨,Woolster,我有一个问题。设计师决定使用两个加法而不是乘法,可能是因为性能问题,正如你所说的那样。但是,为什么设计师无论如何都要使用4倍乘法呢?当然,数组中的数字是32位整数。因此,它们是4字节大,但我们不知道变量i、j和k有多大。也许它们每个都是4字节大。那么我们就不需要将A[]乘以4来获取下一个值了吗?我认为设计师假设这些变量是1字节大。这可能是真的吗? - user2965601
@user2965601 变量被保存在寄存器中。MIPS寄存器都是4字节大小的。如果这些寄存器中的值小于256,那么这并不改变寄存器最多可以包含4个字节的事实。此外,仍然需要乘以4,以便代码将数据写入正确的数组位置。 - puppydrum64

0

我有一个答案。循环中,a是元素数组,其基本地址为:0x0FE3B128。 非常感谢大家的帮助。 这是我的作业,我不确定它是否正确。

    for(i=1; i!=20;i+=3){
        a[i]= a[5]+1;
        }
lui    $s0, 0x0FE3
ori    $s0, $0, B128
lw     $t1, 20($s0)
addi   $s1, $0, 1
addi   $s2, $0, 20
LOOP     beq $s1, $s2, DONE
         add $t1, $t1, $s1
         sll $t1, $t1, 2
         sw   $t2, 0($t1)
         addi  $s1, $0, 3
          j LOOP
DONE


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接